NESNE YÖNELİMLİ PROGRAMLAMA HAFTA # 6
SINIFLARIN TEKRAR KULLANILMASI Belli bir amaç için yazılmış ve doğruluğu kanıtlanmış olan sınıfları, yeni uygulamaların içerisinde kullanmak avantajlıdır: iş süresini kısaltır yeni yazılan uygulamalarda hata çıkma riskini en aza indirger. Bunun iki yöntemi bulunur: 1. Komposizyon 2. Kalıtım (inheritance)
Komposizyon Elma sınıfı, Meyva sınıfını doğrudan kendi içerisinde tanımlayarak, Meyva sınıfının içerisindeki erişilebilir olan özellikleri kullanabilir. Burada yapılan iş Elma sınıfını Meyva sınıfına bağlamaktır.
Komposizyon Sınıfların arasındaki ilişki UML diyagramında gösterilirse;
Komposizyon Örn#2
Komposizyon Örn#2 AileArabası sınıfının içerisine, Motor tipinde global bir alan yerleştirilerek, bu iki sınıf birbirine bağlanmış oldu. AileArabası sınıfının hereketet() ve dur() metotlarında, önce Motor sınıfına ait yordamlar direk olarak çağrıldı.
Komposizyon Örn#2 Sınıfların arasındaki ilişki UML diyagramında gösterilirse;
Komposizyon Örn#2 Ekran çıktısı:
Komposizyon Örn#3 Voltran sınıfı 6 değişik sınıf tarafından oluşturulmaktadır; bu sınıflara ait özellikler daha sonradan Voltran sınıfının içerisinde ihtiyaçlara göre kullanılıyor.
Komposizyon Örn#3 Sınıfların arasındaki ilişki UML diyagramında gösterilirse;
Kalıtım Java dilinde bir sınıf daha sonra oluşturulacak sınıflarda kullanılabilir. Yeni oluşturulacak sınıfa değişkenleri ve metotları aktarılabilir. Bu şekilde özellik aktarımına kalıtım (inheritance) denir. Öncelikle temel sınıf oluşturulur daha sonra diğer sınıflar bu sınıftan türetilir.
Kalıtım 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ç Anahtar sözcük extends
Kalıtım Kaplan sınıfı bu özelliklerini kendisinin ana sınıfı olan Kedi sınıfından miras almıştır.
Kalıtım Her sınıfın içerisine main yordamı yazarak onları tek başlarına çalışabilir bir hale sokabiliriz (standalone application). Örneğin Kedi sınıfını çalıştırmak için komut satırından java Kedi veya Kaplan sınıfını çalıştırmak için java Kaplan yazılması yeterli olacaktır.
Aşağıda temel bir sınıf olarak Tasit oluşturulmuştur. public class Tasit { private String isim; public Tasit() { isim = " "; } public Tasit(String ilkisim) { isim = ilkisim; } public void setisim(string yeniisim) { isim = yeniisim; } public String getisim() { return isim; }
Tasit sınıfı - devam } public void ciktiyaz() { System.out.println("Isim: " + isim); } public boolean ayniisim(tasit digertasit) { return (this.isim.equalsignorecase(digertasit.isim)); }
Alt Sınıflar Bir sınıf kullanılarak yeni sınıflar oluşturulabilir. Tasit sınıfı kullanılarak Otomobil sınıfı oluşturulmuştur. public class Otomobil extends Tasit{ private int plakano; public Otomobil() { super(); plakano = 0; } public Otomobil(String marka, int plakanumarasi) { super(marka); plakano = plakanumarasi; }
Otomobil sınıfı - devam public void reset(string yenimarka, int yeniplakanumarasi) { setisim(yenimarka); plakano = yeniplakanumarasi; } public int getotomobilplakasi() { return plakano; } public void setplakanumarasi(int yeniplakanumarasi) { plakano = yeniplakanumarasi; }
Otomobil sınıfı - devam } public void ciktiyaz() { System.out.println("Marka: " + getisim()); System.out.println("Plaka Numarasi: " + plakano); } public boolean equals(otomobil digerotomobil) { return (this.ayniisim(digerotomobil) && (this.plakano == digerotomobil.plakano)); }
Alt Sınıflar Otomobil sınıfı içindeki public class Otomobil extends Tasit satırı ile Tasit sınıfının özelliklerini kullanan Otomobil adında yeni bir sınıf türetilmiştir. Bu tanımdan sonra Otomobil c = new Otomobil; tanımı yapıldığında, c.setisim( Fiat ); geçerli bir tanım olacaktır.
Aşağıdaki örnekte Tasit ve Otomobil sınıflarının kullanımı görülmektedir. public class KalitimDemo { } public static void main(string[] args) { } Otomobil c = new Otomobil(); c.setisim("fiat"); c.setplakanumarasi(1234); c.ciktiyaz(); Çıktı: Marka: Fiat Plaka Numarası: 1234
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.
Gizli Kalıtım Ekran çıktısı:
Gizli Kalıtım YeniBirSinif 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.
Gizli Kalıtım Bu sayede Object nesnesine ait erişebilir yordamları kullanabiliriz. Object nesnesine ait bazı yordamlar aşağıdaki gibidir: equals(object obj): obj referansına bağlı olan nesnenin, kendisine (this) eşit olup olmadığı kontrolü yapan yordam. finalize(): Çöp toplayıcısı tarafından silinmeden önce çalıştırılan yordam. getclass(): Bu nesnenin (this) çalışma anındaki sınıf bilgilerini Class nesnesi şeklinde geri döner. tostring(): Bu nesnenin (this), String tipindeki ifadesini geri döner.
Gizli Kalıtım Akıllara şöyle bir soru gelebilir, Kaplan sınıfı hem Kedi sınıfından hem de Object sınıfından mı türemiştir? Cevap hayır Java programlama dilinde çoklu kalıtım (multiple inheritance) yoktur. Aşağıdan yukarıya doğru gidersek, Kaplan sınıfı Kedi sınıfından türemiştir, Kedi sınıfa da Object sınıfından (gizli ve otomatik olarak) türemiştir. Sonuçta Kaplan sınıfı hem Kedi sınıfının hem de Object sınıfına ait özellikler taşıyacaktır.
Kalıtım ve İlk Değer Alma Sırası Ekran çıktısı:
EKRAN ÇIKTISI Hayvan SINIFI YAPICISI DortAyakli SINIFI YAPICISI Otcul SINIFI YAPICISI
Superclass Yapılandırıcısı Miras alınan sınıf Superclass Miras alan sınıf Subclass Herbir subclass, superclass olma adayıdır. Subclass ın bir üstündeki sınıf Direct Superclass Diğer superclass lar Indirect Superclass
Super Deyimi Hiyerarşide üst sınıflara çıkıldıkça, en üst sınıftan aşağıya doğru tüm yapılandırıcılar çalışmakta fakat değerleri aktarılmamaktadır. Bir sınıftan türeyen sınıfın yapılandırıcısı türediği sınıfın yapılandırıcısını 'super()' şeklinde çağırabilir. Bu şekilde super class a veri aktarılmış olur.
Ucgen sınıfından bir nesne 3 parametre alan yapıcı metodu ile oluşturulduğunda ilk 2 parametre ana sınıftaki yapılandırıcıya aktarılmış, böylece Sekil sınıfından türetilen nesnelerin ortak özelliği olan Taban ve Yuksekliği türeyen sınıfın içinde tekrar bildirme zorunluluğu ortadan kaldırılmıştır.
Parametre Alan Yapılandırıcılar ve Kalıtım Ekran çıktısı: aynı this anahtar kelimesinin kullanılışı gibi super anahtar kelimesi de içinde bulunduğu yapılandırıcının ilk satırında yer almalıdır.
Parametre Alan Yapılandırıcılar ve Kalıtım
Parametre Alan Yapılandırıcılar ve Kalıtım
Komposizyon mu? Kalıtım mı? Komposizyon, daha evvelden yazılmış sınıfların özelliklerini kullanmak için temiz bir yöntemdir.
Komposizyon mu? Kalıtım mı? 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 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.
İptal Etmek (Overriding) Uygulamamızın çıktısı aşağıdaki gibi olur;
İptal Etmek (Overriding) sayfasayisiogren() ve fiyatogren() yordamlarını hem ana sınıfın içerisine (Kitap2) hemde ana sınıfdan türeyen yeni sınıfın içerisine (Roman2) yazmış olduk. Uygulamayı derleyip, çalıştırınca, ekrana basılan sonuç aşağıdaki gibidir;
İptal Etmek (Overriding) iptal eden yordamın CepTelefonu.aramaYap(), iptal edilen yordamın Telefon.aramaYap() erişim belirleyicisi ile aynı veya daha erişilebilir bir erişim belirleyicisine sahip olması gerektiği belirtiliyor
İptal Etmek (Overriding) En erişilebilir erişim belirleyicisinden, en erişilemez erişim belirleyicisine doğru sıralarsak; public : Her yerden erişilmeyi sağlayan erişim belirleyicisi. protected : Aynı paket içerisinden ve bu sınıfdan türemiş alt sınıflar tarafından erişilmeyi sağlayan erişim belirleyicisi. friendly : Yalnızca aynı paket içerisinden erişilmeyi sağlayan erişim belirleyicisi. private : Yalnızca kendi sınıfı içerisinden erişilmeyi sağlayan, başka her yerden erişimi kesen erişim belirleyicisi.
İptal Etmek (Overriding) Olaylara bu açıdan bakarsak, ana sınıfa ait a() isimli public erişim belirleyicisine sahip bir yordam var ise, bu sınıftan türeyen bir alt sınıfın, ana sınıfa ait a() yordamını iptal etmek için, erişim belirleyicisi kesinlikle public olmalıdır. Eğer aynı a() yordamı protected erişim belirleyicisine sahip olsaydı, o zaman türeyen alt sınıfın bu yordamı iptal edebilmesi için erişim belirleyicisini public veya protected yapması gerekecekti.
İptal Etmek (Overriding) HesapMakinesi sınıfı içerisinde tanımlanan ve friendly erişim belirleyicisi olan hesapla() yordamı, türeyen alt sınıf içerisinde iptal edilmiştir (override). Bu doğrudur; çünkü, protected erişim belirleyicisi, friendly erişim belirleyicisine göre daha erişilebilirdir.
Alt Sınıflarla Programlama Yaklaşımları Bir alt sınıf içindeki bir metodun çağırılması için this anahtar kelimesi kullanılmalıdır. public Otomobil(String ilkisim) { this( Fiat, 1234); } Bu durumda Otomobil sınıfındaki public Otomobil(String marka, int plakanumarasi) metodu çağırılmış olur. Bir üst sınıf içinde temel sınıfın metodu super.ciktiyaz(); şeklinde çağırılabilir.
Alt Sınıflarla Programlama Yaklaşımları Önceki örnekte çiktiyaz() metodu aşağıdaki gibi yapılandırılabilir. public ciktiyaz() { super.ciktiyaz(); System.out.println( Plaka Numarası: + plakano); } Bu durumda önce Tasit sınıfındaki ciktiyaz() metodu çalışacak ardından Otomobil sınıfındaki işlemler yapılacaktır.
Birden Fazla Seviyeli Kalıtım Otomobil sınıfından bir alt sınıfı olarak Sedan adlı bir sınıf oluşturulmuş olsun. Yeni oluşturulan Sedan alt sınıfı hem Otomobil sınıfının hem de Tasit sınıfının metotlarını kullanabilecektir.
Örnek - Sedan - devam public class Sedan extends Otomobil { private int fiyat; public Sedan() { super(); fiyat = 10000; } public Sedan(String marka, int plakano, int ilkfiyat) { super(marka, plakano); setfiyat(ilkfiyat); }
Örnek - Sedan - devam public void reset(string yenimarka,int yeniplakano,int yenifiyat) { reset(yenimarka,yeniplakano); setfiyat(yenifiyat); } public getfiyat() { return fiyat; } setfiyat(int yenifiyat) { fiyat = yenifiyat; }
Örnek - Sedan - devam public void ciktiyaz() { super.ciktiyaz(); System.out.println("otomobil fiyati " + fiyat); } } public boolean equals(sedan digersedan) { return(super.equals(digersedan)&&(this.fiyat == digersedan.fiyat)); }
Birden Fazla Seviyeli Kalıtım Aşağıdaki nesne kurucusu 3 değişken almaktadır. Metot içerisinde, Otomobil ana sınıfına ait nesne kurucusu iki parametreyle çağırılmaktadır. public Sedan(String marka, int plakano, int ilkfiyat) { super(marka, plakano); setfiyat(ilkfiyat); } Sedan sınıfı içindeki reset() metodu 3 parametreye sahiptir ve kendi içinden Otomobil sınıfı içindeki ik parametreye sahip reset() metodunu çağırmaktadır. public void reset(string yenimarka,int yeniplakano,int yenifiyat) { reset(yenimarka,yeniplakano); setfiyat(yenifiyat); }
Örnek KalitimDemo public class KalitimDemo2 { public static void main(string[] args) { Sedan c = new Sedan("Toyota", 1234, 10000); c.ciktiyaz(); } } Çıktı: Marka: Toyota Plaka Numarası: 1234 Otomobil fiyati 10000
Farklı paketler içerisindeki sınıflar için iptal Öncelikle HesapMakinesi ve Bilgisayar sınıflarını public sınıf yapıp ayrı ayrı dosyalara kayıt edelim ve bunları farklı paketlerin altına kopyalayalım.
Farklı paketler içerisindeki sınıflar için iptal
Farklı paketler içerisindeki sınıflar için iptal tr.edu.kou.util paketinin içerisindeki türeyen Bilgisayar sınıfının protected erişim belirleyicisine sahip olan hesapla() yordamı, tr.edu.kou.math paketinin içerisindeki HesapMakinesi sınıfının friendly erişim belirleyicisine sahip olan hesapla() yordamını iptal edemez. Çünkü türeyen sınıf (Bilgisayar) bu yordamın varlığından bile haberdar değildir. Bilgisayar sınıfının içerisindeki hesapla() yordamı, tamamen Bilgisayar sınıfına ait ayrı bir yordamdır. İşte bu yüzden tr.edu.kou.util paketinin içerisindeki türeyen Bilgisayar sınıfının içerisindeki hesapla() yordamı, kendisinin ana sınıfı olan HesapMakinesi sınıfının hesapla() yordamını iptal etmekten (override) gayet uzaktır.
Farklı paketler içerisindeki sınıflar için iptal Bilgisayar.java dosyasındaki yorum kısmını kaldırarak derlemeye çalışırsak, aşağıdaki hata mesajı ile karşılaşırız:
İptal Etmek (Overriding) vs. Adaş Yordamlar (Overload) Uygulamanın sonucu : Buradaki yanlışlık, yordamların parametrelerindeki farklılıktan doğmaktadır. Kodu yazan kişi, ana sınıfa ait olan isyap() yordamı iptal ettiğini kolaylıkla zannedebilir ama aslında farkına bile varmadan adaş yordam (overloaded) oluşturmuştur.
Yukarı Çevirim (Upcasting) KontrolMerkezi sınıfının statik bir yordamı olan checkup(), Sporcu sınıfı tipinde parametre kabul etmektedir. Buradaki ilginç olan nokta checkup() yordamına, Futbolcu sınıfı tipindeki referansı gönderdiğimizde hiç bir hata ile karşılaşmamamızdır. Burada bir hata yoktur çünkü her Futbolcu bir Sporcudur.
Final Özelliği Final kelimesinin sözlük anlamı "son" demektir. Java programlama dilindeki final anahtar kelimesi de değiştirilemezliği simgeler. Değiştirilemezliğin seçilmesi iki sebepten dolayı olabilir, tasarım verimlilik Final özelliği şu yapılara uygulayabiliriz: Global olan alanlar yordamlar sınıflar
Global Alanlar ve Final Özelliği Uygulamanın sonucu aşağıdaki gibi olur:
Final Parametreler Bu uygulamamız, dışarıdan iki parametre alarak bunları ilkel olan int tipine çeviriyor. Eğer dışarıdan eksik veya fazla parametre girilmiş ise kullanıcı bu konuda uyarılıyor.
Boş (Blank) Final Boş final alanlara ilk değerleri yapılandırıcıların içerisinde verilemelidir; statik olan global alanlar boş final olma özelliğinden yararlanamazlar.
final Yordamlar Ana sınıf içerisindeki bir yordamın, alt sınıflar tarafından iptal edilmesi istenmiyorsa, o yordamı final yaparak korunabilir. Kısacası final yordamlar iptal edilemezler.
Final Sınıflar Bir sınıfı final yaparak, bu sınıftan türetilme yapılmasını engellemiş oluruz.
Kalıtım (Inheritance) ve İlk Değer Alma Sırası Java programlama dilinde her sınıf kendi fiziksel dosyasında durur. Bir fiziksel.java dosyasının içerisinde birden fazla sınıf tanımlanabilir. Uygulama tarafından kullanılan bu sınıflar, bulundukları fiziksel dosyalarından bir seferde topluca sınıf yükleyicisi tarafından belleğe yüklenmezler. Bunun yerine hangi sınıfa ihtiyaç duyuluyor ise, bu sınıf CLASSPATH değişkenin gösterdiği yerlere bakılarak yüklenilmeye çalışılır.
Kalıtım (Inheritance) ve İlk Değer Alma Sırası Peki bir sınıf tam olarak ne zaman yüklenir? Cevap Bir sınıfa ait statik global alan veya statik bir yordam çağrıldığında, bu sınıf, sınıf yükleyicisi (Class Loader) tarafından yüklenir veya bir sınıfa ait bir nesne oluşturmak istersek yine sınıf yükleyicisi (Class Loader) devreye girerek bu sınıfı yükler
Kalıtım (Inheritance) ve İlk Değer Alma Sırası