|
~BöLÜM-5~ |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sınıfların Tekrardan KullanılmasıBelli bir amaç için yazılmış ve doğruluğu kanıtlanmış olan sınıfları , yeni uygulamaların içersinde kullanmak, hem iş süresini kısaltacaktır hemde yeni yazılan uygulamada hata çıkma riskini minimum'a indirecektir. Uygulamalarımızda daha evvelden yazılmış ve doğruluğu kanıtlanmış olan sınıfları tekrardan kullanmanın iki yöntemi vardır. Birinci yöntem komposizyon'dur.Bu yöntemde daha önceden yazılmış ve doğruluğu kanıtlanmış olan sınıf tipindeki değişkenimizi , yeni yazılan sınıfın içersinde doğrudan kullanabiliriz. Daha önceki bölümlerde komposizyon yöntemini çokca kullandık. İkinci yöntem ise kalıtımdır(inheritance) , bu yöntemde yeni oluşturacağımız sınıfı , daha evvelden yazılmış ve doğruluğu kanıtlanmış olan sınıfıdan türetiriz, böylece yeni oluşan sınıf , türetildiği sınıfın özelliklerine sahip olur , artı , oluşan bu yeni sınıf kendisine ait yeni özelliklerde ekleyebilir. KomposizyonKomposizyon yönetmini daha önceki örneklerimizde kullandık , baştan ne olduğu bilinçli bir şekilde örnek üzerinde açıklarsak ; gösterim-1
gösterim-2
Elma sınıfı , Meyva sınıfını direk olarak kendi içersinde tanımlayarak, Meyva sınıfının içersindeki özellikleri erişebilir .Burada yapılan iş Elma sınıfını Meyva sınıfına bağlamaktır. Sınıfların arasında ilişkiyi UML diyagramında gösterirsek
Şekil-1
Başka bir örnek verirsek ; ör-Motor.java
Şimdi bu motor sınıfını , arabamızın içersine yerleştirelim ; ör-AileArabasi.java
AileArabası sınıfının içersine Motor tipinde global değişken yerleştirerek , iki sınıfı birbirine bağlamış olduk.AileArabası sınıfının hereketEt() ve dur() metodlarında, önce Motor sınıfına ait metodlar direk olarak çağrıldı.Bu ilişkiyi UML diyagramında incelersek .
Şekil-2
Motor sınıfının private erişim belirliyicisine sahip olan motor_gucu değişkenine , AileArabasi sınıfından ulaşamayız,nedenlerini bir önceki bölümde incelemiştik. AileArabasi sınıfı Motor sınıfının sadece iki adet public metoduna erişebilir , calis() ve dur().Olaylara kuş bakışı bakarsak , karşımızdaki manzara aşağıdaki gibidir.
Şekil-3 AileArabasi sınıfını çalıştırırsak , ekrana gelen çıktının aşağıdaki gibi olması gerekir;
Komposizyon yöntemine en iyi örnek , bir zamanların ünlü çizgi filmi Voltran'dır. Bu çizgi filmi hatırlayanlar bileceklerdir ki , büyük ve yenilmez olan robot'u (Voltran) oluşturmak için değişik ufak robotlar biraraya gelmekteydi. Kollar , bacaklar ,gövde ve kafa bölümü. Bizde kendi Voltranımızı oluşturalım ; ör-Voltran.java
Voltran sınıfı , 6 değişik sınıf tarafından oluşturulmaktadır.6 değişik sınıf'a ait özellikler daha sonradan Voltran sınıfının içersinde ihtiyaçlara göre kullanılıyor.Oluşan olayları UML diyagramında tanımlarsak ; Şekil-4 KalıtımKalı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ıfdan diğer bir sınıfın türemesidir. Yeni türeyen sınıf , türetilen sınıfın global değişkenlerine (statik veya değil ) ve metodlarına (statik veya değil) otomatik olarak sahip olur (private olanlar hariç). Unutulmaması gereken nokta , yeni türeyen sınıf , türetilen sınıfın private global değişkenlerine (statik veya değil ) ve metodlarına (statik veya değil ) otomatik 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 belirliyicisine sahip olan global değişkenlerine (statik veya değil ) ve metodlarına (statik veya değil ) otomatik olarak sahip olabilir. gösterim-3
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 biseyler eklemiştir. Yazılış ifadesi olarak , türeyen sınıf isminin yanına extends ifadesini koyarak , hemen sonrasında türetilen sınıfın kendisini yerleştiririz.Yukarıdaki örneğimizi UML diyagramında göstermeye çalışırsak ;
Şekil-5 Kedi ve Kaplan sınıflarımızı biraz daha geliştirelim ; ör-KediKaplan.java
Kaplan sınıfı Kedi sınıfından türemiştir.Görüldüğü üzere Kaplan sınıfının içersinde ne yakalaAv() metodu ne de ayaksayisi değişkeni tanımlanmıştır. Kaplan sınıfı bu özelliklerini kendisinin ana sınıfı olan Kedi sınıfından almıştır. Kedi sınıfının içersinde tanımlanmış ayaksayisi değişkeni , protected erişim belirliyicisine sahiptir.Bunun anlamı , bu değişkene aynı paket içersinde olan sınıflar ve ayrı paket içersinde olup bu sınıftan türetilmiş olan sınıfların erişebileceğidir.Böylece Kaplan sınıfı ister Kedi sınıfı ile aynı pakette olsun ister olmasın , Kedi sınıfına ait global int ilkel (primitive) tipinindeki değişkene (ayaksayisi) erişebilir. Her sınıfın içersine main metodu yazarak onları tek başlarına çalışabilir bir hale sokarız (standalone application) ,bu yöntem sınıfları test etmek açısından iyidir.Örneğin Kedi sınıfını çalıştırmak için java Kedi veya Kaplan sınıfını çalıştırmak için java Kaplan dememiz yeterli olacaktır. Gizli KalıtımOluşturduğumuz her yeni sınıf otomatik ve gizli olarak Object sınıfından türer.Object sınıfı Javadaki tüm diğer sınıfların ana sınıfıdır. ör-YeniBirSinif.java
Uygulamamızın çıktısı aşağıdaki gibi olur ;
YeniBirSinif sınıfımızda , toString() ve equals() metodları tanımlanmamasına rağmen bu metodları kullandık , nasıl ? . Biz yeni bir sınıf tanımladığımızda , Java gizli ve otomatik olarak extends Object , ibaresini yerleştirir. gösterim-4
Bu sayede Object sınıfına ait metodları kullanabiliriz. Object sınıfına ait obje metodları aşağıdaki gibidir ;
Kısacası , oluşturululan her yeni sınıf , yukarıdaki , metodlara otomatik olarak sahip olur . Bu metodları yeni oluşan sınıfların içersinde tekrardan istediğimiz gibi yazabiliriz.Örneğin finalize() metodu kendi sınıfımızın içersinde farklı sorumluluklar verebiliriz(çizgi çizen bir objenin , hafızadan silinirken çizdiği çizgileri temizlemesi gibi) . Bu olaya , ana sınıfın metodlarını iptal etme (override) denir. Biraz sonra iptal etme(override) konusunu daha detaylı inceliyeceğiz. Akıllara şöyle bir soru gelebilir , Kaplan sınıfı hem Kedi sınıfından hemde 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ıfada Object sıınıfından (gizli ve otomatik olarak). Sonuçta Kaplan sınıfı hem Kedi sınıfının hemde Object sınıfına ait özellikler taşıyacaktır . Aşağıdaki şeklimizde görüldüğü üzere her sınıf sadece tek bir sınıfdan türetilmiştir.Object sınıfı tüm sınıfların türetildiği en tepedeki sınıfıdır.
Şekil-6 Çoklu kalıtım (multiple inheritance) , bazı konularda faydalı olmasının yanında bir çok sorun oluşturmaktadır. Örneğin iki ana sınıf düşünün , bunların aynı isimde değişik işlemler yapan metodları bulunsun.Bu olay türetilen sınıfın içersinde bir çok probleme yol açacaktır. Bu sebeblerden dolayı Java programlama dilinde çoklu kalıtım yoktur. Java programlama dilinde çoklu kalıtım'ın faydalarından yararlanmak için interface kavramı kullanılır.Interface kavramını ilerleyen bölümlerde inceliyeceğiz. Kalıtım ve ilk değer alma sırasıTek bir sınıf içersinde ilk değerlerin nasıl alındığını geçmiş bölümlerde incelimiştik (bkz). İşin içersine birde kalıtım kavramı girince olaylar biraz karışabilir.Kalıtım kavramı bir sınıfdan , başka bir sınıf kopyalamak değildir. Kalıtım kavramı türeyen bir sınıf , türetilen ana sınıfın özelliklerini taşır ama kendisine ait değişik özelliklerde taşıyabilir. Bir Obje oluşurken , bu objeye ait yapılandırıcının çağrıldığını önceki bölümlerden biliyoruz , peki aynı olaya birde kalıtım kavramı ile birlikte bakalım ; ör-IlkDegerVermeSirasi.java
UcanYarasa objesi oluşmadan evvel , UcanYarasa sınıfının ana sınıfı olan Yarasa objesi oluşturulmaya çalışılacaktır.Fakat Yarasa sınıfıda Hayvan sınıfından türemiştir , Yarasa sınıfının ana sınıfı Hayvan sınıfıdır . Hayvan sınıfıda Object sınıfından türemiştir .
Şekil-7 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 fark edildiği üzere varsayılan yapılandırıcıdır (default constructor).Uygulamanın çıktısı aşağıdaki gibi olacaktır ;
Paremetre alan yapılandırıcılar ve kalıtımParametre alan yapılandırıcıları , İşin içersine kalıtım girdiğinde direk olarak çağıramayız , bu yapılandırıcıları çağırmak için özel bir ifade kullanmamız gereklidir. Ana sınıfın parametre alan yapılandırıcısı açık olarak super anahtar kelimesi ile çağırmak gereklidir. ör-IlkDegerVermeSirasiParametreli.java
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.
Dikkat edilmesi gereken ikinci husus , aynı this anahtar kelimesinin kullanılışı gibi , super anahtar kelimeside içinde bulunduğu yapılandırıcının ilk satırında yer almalıdır. ör-IlkDegerVermeSirasiParametreli.java-hatalı
IlkDegerVermeSirasiParametreli.java örneğini derlerseniz ; gösterim-5
Aşağıdaki derleme-anı (compile-time) hatası ile karşılaşırsınız.
Komposizyon mu ? Kalıtım mı ?Yeni oluşturduğunuz sınıfın içersinde , 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.Yeni oluşturulan sınıfın içersinde , kullanmak istediğimiz sınıflara ait değişkenler tanımlıyarak istediğimizi elde ederiz. ör-Araba.java
Peki ya kalıtım kavramını ne zaman kullanmalıyız ? Daha evvelden yazılmış biri sınıfın , belli bir problem için yeni versiyonunu yazma işlemi , kalıtım kavramını yeterince açıklar. 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 Elma ve Meyva sınıflarını göz önüne alırsak , şöyle bir söz yanlış olmaz sanırım, Elma bir Meyvadır . Bu iki sınıf arasında "bir" ( is -a ) ilişkisi olduğundan , kalıtım kavramını bu sınıflar üzerinde rahatca kullanabiliriz. Örnekleri çoğaltmak mümkündür. UçanYarasa , Yarasa ve Hayvan arasındaki ilişkiyi açıklarsak ;
İptal etmek (Overriding)Ana sınıf içersinde tanımlanmış bir metod ,bu ana sınıfdan türeyen bir sınıf içersinde iptal edilelebilir. ör-KitapEvi.java
Uygulamamızı javac KitapEvi.java komutu ile derlenikten sonra , java Roman komutunu çalıştırdığımızda , uygulamanın çıktısı aşağıdaki gibi olur ;
Roman sınıfının içersinde sayfaSayisiOgren() ,fiyatOgren() , yazarIsmiOgren() metodları olmamasına rağmen çağırabildik.Bunun sebebinin kalıtım olduğu biliyoruz. Türeyen sınıf , türediği sınıfa ait global değişkenleri (statik veya değil) ve metodları (statik veya değil) kendisine alır (private ve final olanları alamaz, ve aynı paket içinde değilse friendly olanlarıda alamaz ,sadece protected olanları alabilir ). KitapEvi.java örneğimizde Roman sınıfının yaptığıda tam olarak budur.Peki şimdi Roman sınıfının içersinde sayfaSayisiOgren() ve fiyatOgren() adında iki metod oluşturabilirmiyim ? Oluşturursam nasıl etkiler meydana gelir ? Aynı örneğimizin ikinci bir versiyonunu yazalım ; ör-KitapEvi2.java
sayfaSayisiOgren() ve fiyatOgren() metodlarından hem ana sınıfın içersine (Kitap) hemde ana sınıfdan türeyen yeni sınıfın içerisine (Roman) yazmış olduk . Peki bu durumda uygulamanın ekrana basacağı sonuç nasıl olur ? Uygulamamızı derleyip , çalıştırınca , ekrana basılan sonuç aşağıdaki gibidir ;
Roman sınıfının içersinde , ana sınıfa ait metodların aynısını tanımladıktan sonra , Roman sınıfının sayfaSayisiOgren() ve fiyatOgren() metodlarını çağrınca , artık otomatik olarak ana sınıfın metodları devreye girmedi , bunun yerine Roman sınıfının sayfaSayisiOgren() ve fiyatOgren() metodları devreye girdi.Yani Roman sınıfı , türetiği sınıfın (Kitap) sayfaSayisiOgren() ve fiyatOgren() metodlarını iptal etmiş oldu . Ana sınıfa ait metodları iptal ederken dikkat edilmesi gereken önemli hususlardan biri erişim belirliyicilerini iyi ayarlamaktır.Konuyu hatalı bir örnek üzerinde gösterirsek ; ör-Telefonlar.java
Yukarıdaki örneğimizi derlediğimizde, Java bizi şöyle bir hata mesajı verecektir ;
Bu hatanın türkçe açıklaması ; iptal eden metodun -CepTelefonu.aramaYap()- , iptal edilen metodun -Telefon.aramaYap()- erişim belirliyicisinden daha erişilebilir bir erişim belirliyicisene sahip olması gerektiğini belirtir. En erişilebilir erişim belirliyicisinden , en erişilemez erişim belirliyicisine doğu sıralarsak ;
Daha fazla detay için bkz Olaylara bu açıdan bakarsak , ana sınıfa ait a() isimli public bir metod var ise , bu sınıftan türeyen bir sınıf ana sınıfa ait a() metodunu iptal etmek için , erişim belirliyicisi kesin kes public olmalıdır. Eğer aynı a() metodu protected olsaydı , o zaman türeyen sınıf bu metodu iptal etmek için erişim belirliyicisini public veya protected yapabilirdi. ör-Hesap.java
Yukarıdaki örneğimizde , ana sınıfa ait olan friendly erişim belirliyicisi olan hesapla metodu , türeyen sınıf tarafından iptal edilmiştir.Bu doğrudur , çünkü protected erişim belirliyicisi , friendly erişim belirliyicisine göre daha erişilebilirdir.Fakat bu iki sınıf değişik paketlerde olsalardı -ki şu an varsayılan paketin içersindeler - türeyen sınıf (Bilgisayar) ana sınıfın hesapla metoduna ulaşamıyacağından dolayı , iptal etme(overriding) kavramı daha başmadan sona erecekti . Anlatılan olayları bir örnek üzerinde göstermek istersek ; Öncelikle HesapMakinesi ve Bilgisayar sınıfları public sınıf yapıp ayrı ayrı dosyalara kayıt ettek gerekli , daha sonra bunları farklı paketlerin altına kopyalamalıyız. Not : iki ayrı sınıfı değişik paketlere kopyaladim ,özellikle Hesapmakinesi sınıfını public yapmalıyız , yoksa değişik paketlerdeki sınıflar tarafından erişilemez , dolayısıyla kendisinden türetilme yapılamaz. HesapMakinesi sınıfını tr.edu.kou.math , Bilgisayar sınıfını ise tr.edu.kou.util paketinin içersine yerleştirelim ; ör-HesapMakinesi.java
ör-Bilgisayar.java
Yukarıdaki örneklerimizi derleyip , Bilgisayar sınıfını çalıştırırsanız , sorunsuz çalışacaktır. Yukarıda anlatılanlar yalanmıydı diyenler için hemen açıklamamızı yapalım ; tr.edu.kou.util paketinin içersindeki türeyen Bilgisayar sınıfının protected erişim belirliyicisine sahip olan hesapla() metodu , tr.edu.kou.math paketinin içersindeki türetilen HesapMakinesi sınıfının friendly erişim belirliyicisine sahip olan hesapla() metodunu iptal edemez , edemez çünkü türeyen sınıf (Bilgisayar) bu metodun varlığından bile haberdar değildir. tr.edu.kou.util paketinin içersindeki türeyen Bilgisayar sınıfının içersindeki hesapla() metodu , iptal etme kavramından gayet uzaktır. Ayrıca tr.edu.kou.math paketinin içersindeki türetilen HesapMakinesi sınıfının friendly erişim belirliyicisine sahip olan hesapla() metoduna erişemediğimizi ispatlamak için 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) ve adaş metodların(Overload) birbirlerini karıştırılmasıAna sınıfa ait bir metodu iptal etmek isterken yanlışlıkla adaş metodlar yazılabilir. ör-CalisanMudur.java
Her Müdür bir Çalışandır ilkesinden yola çıkılarak yazılmış bu örneğimizdeki büyük hata iki kavramın - (iptal etmek ve adaş metodlarının) - birbirlerine karıştırılmasıdır. Böyle bir hata çok kolay bir şekilde yapılabilir ve fark edilmesi bir o kadar güçtür. Buradaki yanlışlık , metodların parametrelerindeki farklılıktan doğmaktatır , kodu yazan kişi , ana sınıfa ait olan isYap() metodu iptal ettiğini kolaylıkla zannedebilir ama aslında farkına bile varmadan adaş metod oluşturmuştur.Uygulamanın çıktısı aşağıdaki gibidir ;
Yukarı Çevirim (Upcasting)Kalıtım(inheritance) kavramı sayesinde , türeyen sınıf ile türetilen sınıf arasında bir ilişki kurulmuş olur.Bu ilişkiyi şöyle açıklayabiliriz " türeyen sınıfın tipi, türetilen sınıf tipindedir" . Yukarıdaki örneğimizi tekrarlarsak , her elma bir meyvadır, diyebiliriz.Elma ve Meyva sınıfları arasındaki ilişki kalıtım kavramı sayesinde sağlanmış olur. Her elma bir meyvadır veya her müdür bir çalışandır örneklerimiz sadece sözel örnekler değildir , bu ilişki Java tarafından somut olarak desteklenmektedir. Başka bir kalıtım örneğini şöyle açıklayabiliriz , her futbolcu bir sporcudur. Bu ifade bize , Sporcu sınıfının içersindeki metodların otomatik olarak Futbolcu sınıfının içersinde olduğunu söyler, yani Sporcu sınıfına gönderilen her mesaj rahatlıkla Futbolcu sınıfınada gönderilebilir çünkü Futbolcu sınıfı Sporcu sınıfından türemiştir.Eğer Sporcu sınıfının içersinde calis() adında bir metod var ise bu metodun aynısından Futbolcu sınıfının içersinde de olacağı kesindir.Javanın bu ilişkiye nasıl somut olarak destek verdiğini aşağıdaki örneğimizde görebiliriz ; ör-Sporcu.java
KontrolMerkezi sınıfının statik bir metodu olan checkUp() , Sporcu tipinde parametre kabul etmektedir.İlginç olan nokta bu metoda Futbolcu tipindeki obje referansını gönderdiğimizde hiç bir hata ile karşılaşmamamızdır.Burada bir hata yoktur çünkü Her Futbolcu bir Sporcudur.Türetilmiş sınıfın (Futbolcu içersinde kendine has bir çok metod olabilir , ama en azından türediği sınıfın (Sporcu) içersindeki metodlara sahip olacaktır .Sporcu tipinde parametre kabul eden her metod'a Futbolcu tipinde parametre gönderebiliriz. Bu ilişkiyi UML diyagramında gösterirsek ;
Şekil-8 Sporcu.java örneğimizde , türeyen sınıf(Futbolcu) türetildiği sınafa (Sporcu) doğru çevrilmektedir , yani yukarı doğru çevrilmektedir (Upcasting). Yukarı doğru çevirim her zaman güvenlidir , sonuçta daha özel bir tipten daha genel bir tipe doğru daralma vardır. Bu sebebten dolayı yukarı doğru çevrimlerde , özel olarak bir ifade veya belirteç kullanmak zorunda değilizdir. Yukarı çevirim (Upcasting) olayi "Komposiyon mu , Kalıtım mı ? kullanmalıyım" sorusuna da ışık tutmuştur.Sorulması gereken soru "yukarı doğru çevirime ihtiyacım var mi ?" Eger sorunun cevabi "evet" ise , kalitim (inheritance) kullanmamız gerekir. Final KavramıFinal kelimesinin sözlük anlamı "son" demektir.Java programlama dilindeki final kavramıda , sözlük anlamıyla paralel şekilde davranır. Java programlama dilinde final anahtar kelimesi değiştirilemezliği simgiler. Değiştirilemezliğin seçilmesi iki sebebten dolayı olabilir , birincisi tasarım ikincisi ise verimlilik ; Global olan değişkenlere (statik ve değil) , metodlara(statik veya değil) veya sınıflara final kavramını uygulayabiliriz. Global değişkenler ve Final KavramıGlobal değişkenler ile final kavramı birleştiği zaman , ortaya diğer programlama dillerindeki sabit değer özelliği ortaya çıkar.Global olan sabit değişkenler ister statik olsun veya olmasın final özelliğine sahip olabilir. Java programlama dilinde final olan global değişkenlerin değeri derleme anında veya çalışma anında belli olabilir ama dikkat edilmesi gereken husus, final global değişkenlere sadece bir kere değer atanabiliyor olmasıdır.Sonuç olarak global olan final değişkenleri ikiye ayırabiliriz ;
ör-FinalOrnek
Yukarıdaki örneğimizi incelersek , X_SABIT_DEGER ve Y_SABIT_DEGER değişkenlerinin değerlerini derleme anında bilebiliriz , ama A_SABIT_DEGER değişkenin değerini derleme anında bilmek zordur (Math sınıfına ait statik bir metod olan random() , 1 ile 50 arasında rasgele sayılar üretir), bu değişkenin değeri çalışma anında belli olacaktır fakat tüm final özelliğine sahip olan değişkenlere sadece ve sadece bir kere değer atanmaktadır. Bir global değişkene , final ve statik özellikler belirtirseniz , global değişkenimiz , bu sınıfa ait olan tüm objeler için tek olur (bkz) ve değeri sonradan değiştiremez. Final kavramında , ilkel tipdeki değişkenler ile obje tipindeki değişkenlerin arasında büyük bir fark vardır.Yukarıdaki örneğimizi incelerseniz , X_SABIT_DEGER, Y_SABIT_DEGER , A_SABIT_DEGER değişkenleri hep ilkel tipdeydi , yani değerlerini kendi üzerlerinde taşıyorlardı . Kutu tipinde k değişkenimizi final yaptığımızda olaylar biraz değişir, Kutu tipindeki k değişkenini final yaparak , bu değişkenin başka bir Kutu objesine tekrardan bağlanmasına izin vermeyiz ama Kutu tipindeki k değişkeninin bağlı olduğu objenin içeliği değişebilir.Uygulamamızın çıktısı aşağıdaki gibi olur;
Final parametrelerMetodlar'a gönderilen parametre değerlerinin değişmemesini istiyorsak , bu parametreleri final yapabiliriz. ör-FinalParametre.java
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. Daha sonra elimizdeki değerleri FinalParametre sınıfının statik olan topla() metodu gönderiyoruz. Bu metoda gönderilen parametrelerin değiştirilmesi , final ifadeden dolayı imkansızdır. Boş (Blank) FinalJava , final olan obje değişkenlerine ilk değeri verme konusunda acele etmez , fakat final olan obje değişkenleri kullanılmadan önce ilk değerlerinin verilmiş olması şarttır. ör-BosFinal.java
Boş final değişkenlere değerlerini yapılandırıcıların içersinde vermeliyiz.Bir başka nokta ise statik olan global değişkenler boş final olma özelliğinden faydalanamazlar. Final MetodlarTüretilen bir sınıf içersindeki metod tarafından iptal edilme riskini sıfar'a indirmek için , final metodlar yazılabilir. Final metodlar iptal edilemezler. ör-FinalMetod.java
A sınıfına ait ekranaYaz() metodu , A sınıfından türetilmiş B sınıfının ekranaYaz() metodu tarafından iptal edilemez(overriding) . FinalMetod.java örneğini derlemeye çalıştığımızda aşağıdaki hata mesajını alırız ;
private ve finalFinal ve private erişim belirliyicisine sahip olan bir metod , başka bir metod tarafından iptal ediliyormuş gibi gözükebilir. ör-SivilPolis.java
Private erişim belirliyicisine sahip olan metod , dışarıdan erişilemiyeceğinden dolayı , türetilen sınıflar içersindeki metodlar tarafından iptal edilmesi söz konusu değildir.Private erişim belirliyicisine sahip olan bir metod , bir sınıfın gizli ve özel tarafıdır , o sınıfın arayüzü değildir. Bir sınıfın arayüzleri ,o sınıfa ait public ,protected veya friendly erişim belirliyicilerine sahip olan metodlarıdır. Final SınıflarBir sınıfı final yaparak , bu sınıftan kalıtım yapılmasını engellemiş oluruz. Bir sınıfın final yapılmasının iki sebebi olabilir, birincisi tasarım , ikincisi ise verimlilik . Final sınıflar komposizyon yöntemi ile kullanabilirler. ör-Tv.java
Kalıtım (Inheritance ) ve ilk değer alma sırasıDiğer programlama dillerinin coğunda , uygulamanın ihtiyaç duyduğu dosyalar tek seferde toplu olarak, uygulamanın başladığı anda yüklenir ve daha sonra ilk değer alma işlemi başlar . Java ihtiyaç duyduğu dosyaları yükleme işlemine daha değişik bir bakış açısıyla bakar. Javada tüm mantık objeler üzerine
kurulmuştur,ve her sınıf kendi fiziksel dosyasında durur.Java bu sınıf
dosyalarını,uygulama ihtiyaç duyduğu anda yükleme işlemi başlar.Böylece
performans maksimuma çıkartılmış olur.Bir sınıf dosyası ne zaman sınıf
yükleyicisi (Class Loader) tarafından hafızaya yüklenir ? Cevap ; eğer
bir sınıfa ait statik global değişken veya statik bir metod çağrıldığında
, bu sınıf , sınıf yükleyicisi (Class Loader) tarafından yükleni
veya bir sınıfa ait bir obje oluşturmak istersek , önce yükleme işlemi
gerçekleşir. ör-Bocekcik.java
Uygulamanın çıktısı aşağıdaki gibidir ;
Gelişen olayları adım adım açıklarsak ;
Daha sonra statik olan global değiskenlere ilk değerleri verilmeye başlanır. Değer verme işlemi en yukarıdaki sınıfdan başlar ve türemiş sınıflara doğru devam eder (aşağıya doğru) . Burada en yukarıdaki sınıf Bocek sınıfıdır - (Object sınıfını ihmal edersek ) . Bu sonuçlar göz önüne alındığında ekrana çıkan ilk iki satırın aşağıdaki gibi olması gerekir.
Sırada main() metodunun çağrılmasına gelmiştir . Ekrana çıkan üçüncü satır ;
Sonra Bocekcik objesi oluşturulur
( Bocekcik b = new Bocekcik() ). Bu oluşturma sırasında ilk olarak en
yukarıdaki sınıfa (Bocek sınıfı) ait statik olmayan(non-static) degişkenlere ilk
değerleri verilir ve yapılandırıcısı çağrılır. Ekrana çıkan dördüncü
satır
Sorular
Bu dökümanın her hakkı saklıdır. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||