Java Sınıfları
(Classes)
Java’da
sınıf (class) kavramını doğada cins
isimlere benzetebiliriz. Bir cins kendi başına belirli bir nesne değildir;
ancak belirli türden nesnelerin ortak özelliklerini belirten soyut bir
kavramdır. Örneğin, ağaç bir cins isimdir. Ama bahçedeki elma-ağacı ya da
sokaktaki çınar-ağacı belirli varlıklardır. Onlar, ağaç sınıfının birer
nesnesidir (üyesidir). Cinsler alt-cinslere ayrılabilir. Alt-cinsler,
üst-cinslerin özelikleri yanında kendilerine has başka özelikler de taşırlar. Örneğin,
memeli-hayvanlar geniş bir sınıftır. Filler, kaplanlar, şempanzeler,
balinalar, insanlar vb. memeliler sınıfının (üst-sınıf) birer alt-sınıfıdır.
Alt-sınıftakiler, üst-sınıfın özeliklerini taşımakla birlikte, birbirlerinden
kesinlikle farklıdırlar. Her cinsin ve
her alt-cinsin kendine özgü özelikleri (nitelikler ve davranışlar) vardır. Bu
özelikler, onları diğer cinslerden ayırır.
Java’da
sınıfları doğadaki cinsler gibi düşürsek, konuyu kavramamız kolaylaşacaktır.
Java sınıfı, tıpkı bir cinste olduğu gibi, ortak özelikleri belirlenmiş bir
topluluğun adıdır. Bir java sınıfının niteliklerini değişkenlerle (attributes,
fields), davranışlarını metotlarla (fonksiyon, procedure) belirleriz. Başka bir
deyişle, istediğimiz özeliklerini belirterek bir sınıf (cins-isim) tanımlarız.
Bu sınıfın nitelikleri değişkenlerle
(attributes, fields) ve davranışları metotlarla (fonksiyon, procedure) ortaya
konulur. Kısaca, bir java sınıfı kendi özniteliklerini belirleyen değişkenleri
ve fonksiyonları içeren bir birimdir. Bu nedenle, Pascal ve C gibi yapısal
dillerdeki yapı (record, struct) kavramının bir genellemesidir. Record ve
struct yalnızca değişkenler içerebilir. Fonksiyon ve procedure’ler onların
dışında kalır. Java sınıfı ise, değişkenler yanında fonksiyonları da içeren
daha genel bir yapıya sahiptir. Bir sınıf içindeki fonksiyonlar o sınıfın
değişkenlerine erişebildiği gibi, farklı sınıflar arasında da iletişim
sağlanabilmektedir.
Sınıf ve
alt-sınıfların tanımı, bütünüyle programcının gereksemelerine göre yapılabilir.
Alt-sınıflardan başka alt-sınıflar üretilebilir. Böylece en üst-sınıftan
başlayarak en alt-sınıfa ulaşan hiyerarşik bir yapıya sahip olurlar. En alttaki
sınıf, kendisinin üstünde olan bütün sınıfların özniteliklerini taşır. Buna
kalıtım (inheritance) özeliği diyoruz. Bu özelik, Java’nın üstün özeliklerinden
birisidir ve ilerideki konularda nasıl işe yaradığını göreceğiz.
Java
programları sınıf (class) lardan oluşur. Bütün sınıflar aynı yapıya
sahiptirler. Aralarındaki farkı yaratan şey, içerdikleri değişkenler ve
metotlardır. Bazıları hiç değişken ve/veya metot içermez, bazıları az, bazıları
çok değişken ve metot içerebilir.
Uyarı
: Bir sınıftaki değişkenler o sınıfın
niteliklerini, metotlar ise o sınıfın davranışlarını belirler. Bu nedenle, sun
da dahil olmak üzere bazı kaynaklarda değişken terimi yerine nitelem
(attribute), fonksiyon ve procedure yerine de metot terimi kullanılır. Biz de
bu derslerde genellikle bu geleneğe uyacağız. Ama, özellikle değişkeni ve
fonksiyonu vurgulamak gerektiğinde bu gelenekten biraz sapabileceğiz.
Sınıf (Class) Yapısı
Java’da
sınıf (class) yapısı için sözdizimi şöyledir:
[Erişim_nitelemi] class
ad {
Class’ın tanımı
}
Yapının
açıklaması:
[Erişim_belirteci](Access-modifier): Class’a kimlerin erişebileceğini
belirten bir nitelemdir. Bu nitelemleri ve yaptıkları işleri yeri geldikçe
örnekler üzerinde açıklayacağız.
class Sınıf tanımında mutlaka
kullanılması gereken anahtar bir sözcüktür; derleyiciye bir class tanımı
yapıldığını bildirir.
Ad Her
class’a bir ad verilir. Class adlarını büyük harfle başlatmak bir gelenektir.
Buna karşılık, değişken adları, paket adları ve interface adları küçük harfle
başlatılır. Böylece, kaynak programa bakan herkes, neyin class olduğunu hemen
anlayabilir. Bu java programcıları arasındaki bir sözleşmedir ve bu sözleşmenin
java derleyicisi bakımından bir anlamı yoktur. Sözleşme, yalnızca
programcıların kaynak programı okuyup anlamasını kolaylaştırır.
{ } Class’ın
yapısı bu parantezler içinde kurulur; yani class’ın nitelemleri ve metotları
tanımlanır. Bunların nasıl yapıldığını
adım adım göreceğiz.
Java dili
büyük-küçük harf ayrımına duyarlıdır. Anahtar sözcüklerde bu ayrıma dikkat
edilmezse, program derlenemez. Bunun yanında, kaynak programın, okur tarafından
kolay anlaşılması için konulmuş bazı kurallar vardır. Bir tür gelenek halini
alan bu kurallar, derleyici açısından zorunlu olmasa bile, program yazanların
bunlara uyması istenir. Bunlar, java programcıları arsındaki yazısız bir
antlaşma hükümleridir. Böylece, kaynak
programı okuyan herkes, programın yapısını daha kolay kavrayabilir. Bu
kuralları, yeri geldikçe örnekler üzerinde açıklayacağız. Şimdi, basit birkaç
kuralı söylemek gerekiyor.
Uyarı
1.
Java’da adlar
(değişken, metot, class, interface, paket adları) bir karakterle başlar,
karakter veya rakamlarla devam edebilir. Her ad tek sözcükten oluşur; yani ad
olan sözcük boşluk içeremez. Örneğin, Yolcu
12 Treni bir ad olamaz. Bunu Yolcu_12_treni ya da Yolcu12Treni
gibi yazmak gerekir.
2.
İki ya da daha
çok sözcüğün birleştirilmesiyle bir ad yaratılıyorsa, adlar arasına alt-çizgi
(_) simgesi konulur ya da bitişik yazılıp sözcüklerin her birisi büyük harfle
başlatılabilir. Örnekler: Mavi_Yolcu_Treni, MaviYolcuTreni.
3.
Class_adları
büyük harfle başlar, küçük harflerle ya da rakamlarla devam eder.
Örnekler: Tren, Mavi_Tren, Mavi_Yolcu_Treni,
MaviYolcuTreni.
4.
Değişken, metot,
interface ve paket adları küçük harfle başlar.
Örnekler: tren, mavi_Tren,
mavi_Yolcu_Treni, maviYolcuTreni.
5.
Sabitlenmiş
değişkenler büyük harflerle yazılır. Örnek: PI=3.14159.
Hemen
belirtelim ki, java dili, bir programcının gerekseme duyacağı genel türden
class’ları ön-tanımlı olarak içerir. Java’nın içerdiği ve Java API (Application
Programmer’s Interface) denilen bu class’ların dökümanları http://java.sun.com/j2se/1.3/docs/api/ web sitesinden her an görülebilir. Programcı bu
class’ları doğrudan kullanabildiği gibi, dilerse onların alt-class’larını
üretebilir ya da kendi istediği class’ları serbestçe yazabilir. Bu durumuyla,
java dili, programcıya olağanüstü kolaylık ve özgürlük sunmaktadır.
Basiti
anlamak zordur!
Aşağıdaki
class, programcının yazdığı basit bir class’tır. Bu örnek, aslında java dilinin
özelliklerini göstermekten daha çok, o özelikleri saklamaktadır. Ama, her dil
öğretiminde olduğu gibi, konuya sistematik yaklaşmak yerine pedagojik yaklaşmak
daha verimlidir. Bu nedenle, konuyu, basitten karmaşığa giden adımlarla
izleyerek, sonunda asıl sistematik yapıya ulaşacağız.
Jprog01 sınıfı, java API
kütüphanesinde yer alan java.lang
paketi içindeki System class’ını ve java.io paketi
içindeki PrintStream alt-class’ını kullanmaktadır. Aşağıdaki açıklamaları
izleyebilmeleri için, öğrencilerin java API dokümanlarına bakmaları
önerilir.
Jprog01 class’ı
içinde programcının tanımladığı hiçbir değişken veya metot yoktur. Bunun yerine
java API ‘den alınan System sınıfını ve main()
metodunu kullanmaktadır. Ayrıca main()
metodunun çağırdığı System.out.println()
fonksiyonu, parametre olarak bir metin (string) içerdiği için, String class’ını çağırmaktadır. Bütün bu işleri, java kendiliğinden
yapmaktadır. Programcıya düşen tek iş aşağıdaki basit programı yazmaktır. Bu program, aslında bir class yazmaktan ibarettir.
1. class Jprog01
2. {
3. public static void main(String[] args)
4. {
5. System.out.println("Ankara
Türkiye\’nin başkentidir.");
6. }
7. }
Bu programın
çıktısı şudur:
Ankara Türkiye’nin başkentidir.
Çok basit
görünen bu programın açıklanması zor değilse bile, çok uzundur ve java
programının bir çok özeliklerini taşır. Bir java programının (sınıfının) nasıl
çalıştığını göstereceği için bu uzun açıklamaya girmekte yarar görüyoruz.
Java'ya yeni başlayan öğrenciler bu açıklamayı anlayamazlarsa üzülmesinler. Ama
dersler ilerledikten sonra, geri dönüp mutlaka okumalı ve her satırını
anlamalıdırlar. Çünkü, bu açıklamaları kavrayamayan öğrenci, javayı henüz
kavrayamamış demektir.
1.
Satır: Her java programı bir sınıf (class) dır. O nedenle,
hepsi class anahtar sözcüğünü izleyen bir ad ile başlar. (örneğimiz için class
Jprog01 dir). Bazan class anahtar sözcüğünün önüne belirteçler gelebilir. Onları
ileride yeri geldikçe açıklayacağız.
2.
Satır: Java sınıfının tanımı { } parantezi içinde yer alan
ana blok içine konur. 2-inci satırda açılan { parantezi 7-inci satırda kapanmaktadır.
Bu ana bloktur. Bu blokun içine başka bloklar girebilir. Her blokun kendine
özgü { } parantezleri vardır. Açılan her parantez kapatılmalıdır. İç-içe
bloklar oluşturulduğunda, parantezler en içten başlayarak dışa doğru karşılıklı
olarak eşleşirler. Örnekteki 3-üncü satırda başlayan iç blok 6-ıncı satırda
bitmektedir. 3 ile 6-ıncı satırlarda yer alan { } parantezler birbirini eşler
ve bir iç-blok oluşturur. 2-inci ve 7-inci satırlardaki { } parantezleri
birbirine eştir ve en dış bloku (ana blok) oluşturur. Bir sınıf içinde
istenildiği kadar iç-içe bloklar oluşturulabileceği gibi, birbirinin içinde
olmayan bloklar da oluşturulabilir. Ama bütün bloklar, sınıfın sınırlarını
belirleyen ana blok içinde olmak zorundadır.
3.
Satır: Bu satır main() adlı bir metot
(fonksiyon) tanımlamaktadır. public saklı sözcüğü, bir
erişim belirtkesidir, bu metoda her sınıfın ulaşabileceğini belirtir. Gündelik
konuşmamızdaki halka açık deyimine benzer bir işleve sahiptir. Herkes
ona erişebilir. static saklı sözcüğünün java'da
çok işlevsel bir anlamı vardır. Şimdilik, bu belirtkenin, main() metodu için ana
bellekte bir yer ayırdığını ve onun başka bir kopyasının yapılmasına izin
vermediğini söylemekle yetinelim. static saklı sözcüğünün yaptığı işin ayrıntılarını zamanla daha iyi
kavrayacağız. void saklı sözcüğü main() metodunun (fonksiyonunun) değer
bölgesinin olmadığını (boş küme) belirtir. Bu metot bir iş yapar, ama bir değer
almaz. Bazı java metotlarının değer bölgesi vardır, bazılarının yoktur
(boştur). Son olarak main(String[]
args) simgelerini
açıklayalım. Her dilde olduğu gibi, java'da da sınıfın her üyesinin bir adı
vardır. 3-üncü satır bir metot
tanımlamaktadır. Bu metot elbette sınıfın bir üyesi olmaktadır ve bir adı
olmalıdır. Bu metodun adı main()'dir. Java'da bütün
uygulama programları bir main() metodu ile çalışır. Her uygulama programında yalnızca bir tane main() metodu vardır ve
daima 3-üncü satırdaki gibi yazılır. Tabii, her uygulama programı farklı işler
yapacağından, hepsinin main() metodunun tanımı farklı olacaktır. Bu metodun tanımı main(){...}'e ait {...}bloku içinde
yapılır. Ama bütün main()metotlarının adları, nitelemleri ve parametre türü hepsinde
aynıdır. Parantez içindeki String[] args ifadesi bir
değişken (parametre) bildirimidir. Metotların değişkenlerine parametre diyoruz.
Böylece, bu değişkenleri sınıf ve blok içlerinde tanımlanan öteki
değişkenlerden ayırmamız kolaylaşıyor. Değişkenin adı args , tipi ise String[]'dir. String Java'da metin
(text) işlemlerini yapmamızı sağlayan kullanışlı bir sınıf (class) dır. Bununla
çok sık karşılaşacak ve onun bir çok hünerini zamanla öğreneceğiz. Şimdilik,
Pascal ve C gibi dillerde karakter arraylari olarak yapılan metin (string)
işlemlerini java'da String sınıfı ile yaptığımızı söyleyelim. String 'in sonuna [] köşeli
parantezleri eklenince, elde edilen String[] simgesi,
öğeleri String tipinden olan bir dizi
(array) belirtir. Demek ki args değişkeni öğeleri String tipinden olan bir
arraydir. Bunu daha çok açıklamak için,
gerekli ön bilgilere sahip olmayı sabırla beklemeliyiz.
4.
Satır: Bu satırda
metodunun bloku { parantezi ile
başlamaktadır. Blok 6-ıncı satırda bitmektedir, bir iç bloktur. Bu iç blokta
main metodunun tanımı yapılmaktadır.
5.
Satır:
Bu satırın açıklanması için gerekli olan
bilgileri java API dökümanlarından
alabiliriz. Dökümanlarda java.lang paketinin içine
bakarsak, System sınıfını (class)
görebiliriz.
java.lang.System
public
final class System
extends
Object
Dördüncü satırdaki public
erişim belirteci System
sınıfına her sınıfın erişebileceğini söylüyor. final nitelemesi ise, System sınıfının
değiştirilemez (sabit) olduğunu söylüyor. extends Object ifadesi, System
sınıfının Object sınıfından
üretildiğini söylüyor; yani onun bir alt sınıfı olduğunu söylüyor. Object
sınıfı bütün sınıfların üst-sınıfıdır.
Açıklamayı sürdürebilmek için, önce
programın üçüncü satırında yer alan out ‘un ne olduğunu sonra da println()
metodunun tanımını bulmalıyız.
Bunun için, API
dökümanında java.lang paketi içinde yer alan System sınıfının değişkenlerine (attributes,
fields) bakalım. System sınıfının PrintStream
tipinden err ve out adlı iki değişkeni ile InputStream tipinden in
adlı bir değişkeni olduğunu
görürüz. Adlarından da anlaşılacağı üzere, out değişkeni
çıkış akımlarını, in değişkeni giriş akımlarını düzenler. err değişkeni
ise, oluşabilecek hataları bildirir. API dökümanında out değişkenine tıklarsak, onun açık tanımını
görebiliriz:
public static final PrintStream out
Bu değişkenin aldığı public static
final nitemleri , sırasıyla, şu
anlamlara gelir:
public out değişkeni
herkese açıktır. Her class bu değişkene ulaşabilir.
static out değişkeni
için sistem ana bellekte bir yer açmıştır ve kullanılmaya hazırdır. Onu ayrıca
programcının yaratmasına gerek yoktur. Doğrudan kullanılabilir durumdadır.
final out değişkeni sabittir,
program içinde değeri değiştirilemez.
System
sınıfı içindeki out değişkeni static olduğundan,
ona erişmek için
System.out (1)
yazmak yeterlidir. Son olarak, programın
üçüncü satırında yer alan out.println() metodunun
tanımını aramalıyız. Bunun için out
değişkeninin ait olduğu PrintStream
sınıfını bulmalıyız. Bu sınıf java.io
paketi içindedir ve hiyerarşik tanımı şöyledir:
java.io.PrintStream
Bu
hiyerarşiden anlaşılacak şey, PrintStream
sınıfının Object sınıfından türetilen üçüncü
aşamadaki bir alt-sınıf olduğudur. Bu sınıfın tanımı, hiyerarşik olarak şu
tanımlardan çıkar:
public abstract
class OutputStream
extends Object
public class FilterOutputStream
extends OutputStream
public class PrintStream
extends FilterOutputStream
API
dökümanında PrintStream
sınıfının metotları arasında
public void println(String x)
adlı
bir metodu olduğunu görürüz. Bu metot, parametre olarak aldığı bir x metnini standart çıkışa (ekran) yazar. Parametre olarak tırnak
içinde yazdığımız
"Ankara Türkiye\’nin başkentidir."
metni, java için String tipinden bir parametredir (String tipinden x
değişkenidir). println() metodunun
görevi bu parametreyi (nesneyi) byte akışı biçiminde standart çıkışa (ekran)
göndermektir. Böylece,
System.out.println("Ankara Türkiye\’nin
başkentidir.")
deyimi bizim için bir anlam kazanmıştır.