Menu

5 Aralık 2008 Cuma

Kalitim (Inheritance)

Kalıtım konusu nesneye yönelik programlamanın (object oriented programming) en önemli kavramlarından bir tanesidir. Kalıtım kavramı, kısaca bir sınıftan diğer bir sınıfın türemesidir. Yeni türeyen sınıf, türetilen sınıfın global alanlarına ve yordamlarına (statik veya değil) otomatik olarak sahip olur (private olanlar hariç). ()
Unutulmaması gereken unsur, yeni türeyen sınıf, türetilen sınıfın private global alanlarına ve yordamlarına (statik veya değil) otomatik olarak sahip olamaz. Ayrıca yeni türeyen sınıf eğer türetilen sınıf ile ayrı paketlerde ise yeni türeyen sınıf, türetilen sınıfın sadece public ve protected erişim belirleyicisine sahip olan global alanlarına (statik veya değil) ve yordamlarına (statik veya değil) otomatik olarak sahip olur. ()
class Kedi {

//..

}
class Kaplan extends Kedi {

//..

}

Kedi sınıfından türeyen Kaplan sınıfı… İki sınıf arasındaki ilişkiyi şöyle tarif edebiliriz, her Kaplan bir Kedi dir. Yani her kaplan kedisel özellikler taşıyacaktır ama bu özelliklerin üzerine kendisine bir şeyler eklemiştir. ()
Yazılış ifadesi olarak, türeyen sınıf isminin yanına extends ifadesini koyarak, hemen sonrasında kendisinden türetilme yapılan sınıfın kendisini yerleştiririz
Bu konuyu daha iyi bir sekilde pekistirmemiz icin hemen bi ornek yapalim mi :)...

public class Bicycle{
// Bu arada bi hatilatma daha bulunalim, class isimleri herzaman buyuk harfler baslar
public int cadence;
public int gear;
public int speed;

// calssimizi yapilandiralim
public Bicycle(int gear, int speed, int cadence){
this.gear = gear;
this.speed = speed;
this.cadence = cadence;
//this kullanimina baska bir makalede uzun bir yer ayiracaz :)
}
//clasimizin methodlari
public void setCadence(int newValue){
cadence = newValue;
}
public void setGear(int newValue){
gear = newValue;
}
public void speedUp(int increment){
speed +=increment;
}
}
// simdi bicycle clasimizi MountainBike ile extends edeilim
public class MountainBike extends Bicycle{
public int seatHeight;

public MountainBike(int Height, int cadence, int speed, int gear){
// super kullaniminada ayireten deyinecez
super(cadence, speed, gear);
seatHeight = Height;

public void setHeight(int newValue){
seatHeight = newValue;
}
}
Bu ornegimiz faydali olmustur umarum, ama kalitim konusu dedigimiz cok onemli bir konu oldugu icin biraz daha uzerininde durmamiz gerekiyor....

Gizli Kalıtım

Oluşturduğumuz her yeni sınıf otomatik ve gizli olarak Object sınıfından türer. Object sınıfı Java programlama dili içerisinde kullanılan tüm sınıfların tepesinde bulunur. ()
public class YeniBirSinif {
public static void main(String[] args) {
YeniBirSinif ybs1 = new YeniBirSinif();
YeniBirSinif ybs2 = new YeniBirSinif();
System.out.println("YeniBirSinif.toString()" + ybs1 );
System.out.println("YeniBirSinif.toString()" + ybs2 ) ;
System.out.println("ybs1.equals(ybs2)"+ybs1.equals(ybs2)) ;
// ....
}
}
Uygulamamızın çıktısı aşağıdaki gibi olur:
YeniBirSinif.toString() YeniBirSinif@82f0dbYeniBirSinif.toString() YeniBirSinif@92d342ybs1.equals(ybs2) falseYeniBirSinif sınıfımızda, toString()ve equals() yordamları tanımlanmamasına rağmen bu yordamları kullandık, ama nasıl ? Biz yeni bir sınıf tanımladığımızda, Java gizli ve otomatik olarak extends Object, ibaresini yerleştirir. ()

Buradan su anlasiliyorki demekki biz her yazdigimiz uygulamda kalitim kullaniyoruz ama fark etmiyoruz, ama artik biliyoruz gizli kalitimin nasil bisey oldugunu...:)

ornekte verecek olursak hem daha iyi kavrariz hemde kullanabildfigmiz yordamlari ogrenmis oluruz.

public class YeniBirSinif extends Object {

Bu sayede Object nesnesine ait erişebilir yordamları kullanabiliriz. Object nesnesine ait yordamlar aşağıdaki gibidir: ()
clone() :Bu nesnenin(this) aynisini klonlar ve yeni nesneyi dondurur.
equals(Objesc obj) :obj referansina bagli olan nesnenin, kendisine(this) esit olup olmadigini kontrolunu yapar.
finalize() :Cop toplaycisi tarafindan silinmeden once calistirlan son yordam(method).
getClass() :Bu nesnenin caisma anindaki sinizf bilgilerini Class nesnesi seklinde geri dondurur.
hashClass() :Bu nesnenin has kodunu geri doner;
notify(): Bu nesnenin (this), monitöründe olan tek bir iş parçacığını (thread) uyandırır. (ilerleyen bölümlerde inceleyeceğiz) ()
· notifyAll(): Bu nesnenin (this), monitöründe olan tüm iş parçacıklarını (thread) uyandırır. (ilerleyen bölümlerde incelenecektir) ()
· toString(): Bu nesnenin (this), String tipindeki ifadesini geri döner. ()
· wait(): O andaki iş parçacığının (thread) beklemesini sağlar; Bu bekleme notify() veya notifyAll() yordamları sayesinde sona erer. ()
· wait (long zamanAsimi):O andaki iş parçacığının (thread), belirtilen süre kadar beklemesini sağlar (zamanAsimi); bu bekleme notify() veya notifyAll() yordamları sayesinde de sona erdirilebilir. ()
· wait (long zamanAsimi, int nanos):O andaki iş parçacığının (thread), belirtilen gerçek süre kadar (zamanAsimi+ nanos) beklemesini sağlar; bu bekleme notify() veya notifyAll() yordamları sayesinde de sona erdirilebilir. nanos parametresi 0-999999 arasında olmalıdır. ()
Kısacası, oluşturulan her yeni sınıf, yukarıdaki, yordamlara otomatik olarak sahip olur. Bu yordamları yeni oluşan sınıfların içerisinde tekrardan istediğimiz gibi yazabiliriz (uygun olan yordamları iptal edebiliriz-override). Örneğin finalize() yordamı kendi sınıfımızın içerisinde farklı sorumluluklar verebiliriz (çizgi çizen bir nesnenin, bellekten silinirken çizdiği çizgileri temizlemesi gibi). Bu olaya, ana sınıfın yordamlarını iptal etmek (override) denir.

Kalıtım ve İlk Değer Alma SırasıTek bir sınıf içerisinde ilk değerlerin nasıl alındığı 3. bölümde incelenmişti İşin içerisine birde kalıtım kavramı girince olaylar biraz karışabilir. Kalıtım (inheritance) kavramı bir sınıftan, başka bir sınıf kopyalamak değildir. Kalıtım kavramı, türeyen bir sınıfın, türetildiği sınıfa ait erişilebilir olan özellikleri alması ve ayrıca kendisine ait özellikleri tanımlayabilmesi anlamına gelir. Bir sınıfa ait nesne oluşurken, ilk önce bu sınıfa ait yapılandırıcının (constructor) çağrıldığını önceki bölümlerimizden biliyoruz. ()
Verilen örnekte, UcanYarasa nesnesi oluşmadan evvel, UcanYarasa sınıfının ana sınıfı olan Yarasa nesnesi oluşturulmaya çalışılacaktır. Fakat Yarasa sınıfıda Hayvan sınıfından türetildiği için daha öncesinde Hayvan sınıfına ait olan yapılandırıcı çalıştırılacaktır. Bu zincirleme giden olayın en başında ise Object sınıfı vardır. ()

IlkDegerVermeSirasi.java ()
class Hayvan {
public Hayvan() {
System.out.println("Hayvan Yapilandiricisi");
}
}
class Yarasa extends Hayvan {
public Yarasa() {
System.out.println("Yarasa Yapilandiricisi");
}
}
class UcanYarasa extends Yarasa{ public UcanYarasa() {
System.out.println("UcanYarasa Yapilandiricisi");
}
public static void main(String args[]) {
UcanYarasa uy = new UcanYarasa();
}
}


Object sınıfını bir kenara koyarsak, ilk olarak Hayvan sınıfının yapılandırıcısı çalışacaktır, daha sonra Yarasa sınıfının yapılandırıcısı çalışacaktır ve en son olarak UcanYarasa sınıfının yapılandırıcısı çalışacaktır. Bu yapılandırıcıların hepsi, fark edildiği üzere varsayılan yapılandırıcıdır (default constructor). Uygulamanın çıktısı aşağıdaki gibi olacaktır; ()
Hayvan YapilandiricisiYarasa YapilandiricisiUcanYarasa Yapilandiricisi

Parametre Alan Yapilandiricilar ve Kalitim
Ana sinifina ait yapilandirici cagirma islemi, varsayilan yapilandiricilar icin otomatik olarak yurtulen, parametere alan yapilandiricilar icin olay biraz daha degisiiktir. Kisaca Ana sinfin parametre alan yapilandiricisini acik olarak supr anahtar kelimesi ile cagirmak gereklidir. Soyle ki;

// bu ornegi dikkatlice inceleyelim ve super() kullanimia dikkat edin
Class Insan {
public Insan(int par){
System.out.println("Insan yapilandiricisi "+ par);
}
}

class ZekiInsan extends Insan{
public ZekiInsan(int par){
super(par+1);//dikkat
System.out.println("ZekiInsan Yapilandiricisi "+par);

}
}

class Hacker extends ZekiInsan{
public Hacker(int par){
super (par+1);//dikkat
System.out.println("Hacker yapilandiricisi "+par);
}
public static void main(String args[]){
Hacker hck = new Hacker(5);
}
}

Yukarıdaki örneğimizde, her sınıf, yapılandırıcısına gelen değeri bir arttırıp ana sınıfının yapılandırıcısına göndermektedir. Fark edildiği üzere ana sınıfın parametre alan yapılandırıcısını çağırırken super anahtar kelimesini kullandık. Uygulamanın çıktısı aşağıdaki gibidir. ()
Insan Yapilandiricisi 7
ZekiInsan Yapilandiricisi 6
Hacker Yapilandiricisi 5

Bu arda Onemli bir not, super() anahtar kelimesi herzaman bulundugu yapilandiricinin ilk satirda olmak zorundadir.

Komposizyon mu? Kalıtım mı?
Yeni oluşturduğunuz sınıfın içerisinde, daha evvelden yazılmış sınıfların özelliklerinden faydalanmak istiyorsanız bunun iki yolu olduğunu belirtmiştik; Komposizyon ve kalıtım. Peki hangi yöntemi ne zaman tercih etmeliyiz? Komposizyon, daha evvelden yazılmış sınıfların özelliklerini kullanmak için temiz bir yöntemdir.
Peki, kalıtım kavramı ne zaman kullanılır? Daha evvelden yazılmış bir sınıfın, belli bir problem için yeni versiyonunu yazma işleminde, kalıtım kavramı kullanılabilir. Fakat kalıtım konusunda türetilen sınıf ile türeyen sınıf arasında bir ilişki olmalıdır. Bu ilişki "bir" ilişkisidir. Örneğin Kedi ve Kaplan sınıflarını göz önüne alırsak, şöyle bir söz yanlış olmaz sanırım, Kaplan bir Kedidir. Bu iki sınıf arasında "bir" (is -a) ilişkisi olduğundan, kalıtım kavramını bu sınıflar üzerinde rahatça kullanabiliriz. ()
Örnekleri çoğaltmak mümkündür; UçanYarasa, Yarasa ve Hayvan arasındaki ilişki açıklanısa, ()
· UçanYarasa bir Yarasadır;
· Yarasa bir Hayvandır;
· O zaman UçanYarasa'da bir Hayvandır.
· Hayvan'da bir Nesnedir.

Hiç yorum yok:

Yorum Gönder