Java Final Kavramı

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 ;
· Derleme anında değerlerini bilebildiğimiz final global değişkenler.
· Çalışma anında değerlerini bilebildiğimiz final global değişkenler.
ör-FinalOrnek
class  Kutu {
        int i  = 0 ;
}
 
public class FinalOrnek {
 
        final int X_SABIT_DEGER = 34 ;
        final static int Y_SABIT_DEGER = 35 ;
 
        final int  A_SABIT_DEGER  = (int)(Math.random()*50);
 
        final Kutu k = new Kutu() ;
 
        public static void main(String args[]) {
               FinalOrnek fo = new FinalOrnek();
               //fo.X_SABIT_DEGER = 15 ! Hata !
               //fo.Y_SABIT_DEGER = 16 ! Hata !
               //fo.A_SABIT_DEGER = 17 ! Hata !
               fo.k.i = 35 ; // dogru
               // fo.k = new Kutu()  ! hata ! 
               System.out.println("X_SABIT_DEGER = "+fo.X_SABIT_DEGER) ;
               System.out.println("Y_SABIT_DEGER = "+fo.Y_SABIT_DEGER) ;
               System.out.println("A_SABIT_DEGER = "+fo.A_SABIT_DEGER) ;
               System.out.println("Kutu.i = "+fo.k.i) ;
 
        } 
}
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;
X_SABIT_DEGER = 34
Y_SABIT_DEGER = 35
A_SABIT_DEGER = 39
Kutu.i = 35

Final parametreler

Metodlar'a gönderilen parametre değerlerinin değişmemesini istiyorsak , bu parametreleri final yapabiliriz.
ör-FinalParametre.java
public class FinalParametre {
        
    public static int topla(final int a , final int b) {
        // a = 5   ! Hata ! 
        // b = 9   ! Hata !
        return a+b;
    }
 
    public static void main(String args[] ) {
          if ( (args.length != 2 )  ) {
            System.out.println("Eksik veri Girildi") ;
            System.exit(-1); // Uygulamayi sonlandir
          }
          int a = Integer.parseInt(args[0]);
          int b = Integer.parseInt(args[1]);
          int sonuc = FinalParametre.topla(a,b);
          System.out.println("Sonuc = " + sonuc );
    }
}
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) Final

Java , 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
class Kalem { }
 
public class BosFinal {
  final int a = 0; 
  final int b; // Bos final
  final Kalem k; // Blank final obje degiskeni
  // Bos final degiskenler ilk degerlerini 
  // yapilandiricalarda icersinde alirlar
  BosFinal() {
    k = new Kalem();
    b = 1; // bos final degiskenine ilk degeri ver
  }
  BosFinal(int x) {
    b = x; // bos final degiskenine ilk degeri ver
    k = new Kalem();
  }
  public static void main(String[] args) {
    BosFinal bf = new BosFinal();
  }
} 
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 Metodlar

Tü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
 
class A {
    public final void ekranaYaz() {
        System.out.println("A.ekranaYaz()");
    }
}
 
class B extends A {
    public void ekranaYaz() {
        System.out.println("B.ekranaYaz()");
    }
}
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 ;
FinalMetod.java:9: ekranaYaz() in B cannot override ekranaYaz() in A; overridden
method is final
    public void ekranaYaz() {
                ^
1 error

private ve final

Final ve private erişim belirliyicisine sahip olan bir metod , başka bir metod tarafından iptal ediliyormuş gibi gözükebilir.
ör-SivilPolis.java
class Polis {
    private final void sucluYakala() { // gorunmez,gizli metod
        System.out.println("Polis.sucluYakala()");
    }
}
 
public class SivilPolis extends Polis {
    public void sucluYakala() { //iptal etme soz konusu degildir
        System.out.println("SivilPolis.sucluYakala()");
    }
}
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ıflar

Bir 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
final class Televizyon {
    public void kanalBul() {
    }
}
 
/*
class SuperTelevizyon extends Televizyon{
} 
*/
 
class Ev {
    int oda_sayisi = 5 ;
    Televizyon tv = new Televizyon() ;
    public static void main(String args[]) {
        Ev e =  new Ev(); 
        e.tv.kanalBul();
    }
 
}

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.

İşin içersine Kalıtım kavramı girdiğinde , örneğin B sınıfı başka bir sınıfdan türemiş (B extends A ) ise o zaman yükleme sırasında ana sınıf da hafızaya yüklenir - Hem B sınıfı hemde A sınıfı , sınıf yükleyicisi (Class Loader) tarafından yüklenir..

ör-Bocekcik.java
class Bocek {
        int a = 10;
        int b;
        Bocek() {
               ekranaBas("a = " + a + ", b = " + b);
               b = 17;
        }
        static int x1 = ekranaBas("static Bocek.x1 ilk deger verildi");
        static int ekranaBas(String s) {
               System.out.println(s);
               return 18;
        }
}
 
public class Bocekcik extends Bocek {
        int k = ekranaBas("Bocekcik.k ilk deger verildi");
        Bocekcik() {
               ekranaBas("k = " + k);
                ekranaBas("b = " + b);
        }
        static int x2 = ekranaBas("static Bocekcik.x2 ilk deger verildi");
        public static void main(String[] args) {
               ekranaBas("Bocekcik - basla..");
               Bocekcik b = new Bocekcik();
        }
} 
Uygulamanın çıktısı aşağıdaki gibidir ;
static Bocek.x1 ilk deger verildi
static Bocekcik.x2 ilk deger verildi
Bocekcik - basla..
a = 10, b = 0
Bocekcik.k ilk deger verildi
k = 18
b = 17
Gelişen olayları adım adım açıklarsak ;

Öncelikle Bocekcik sınıfına ait statik bir metod olan main() çağrılıyor (java Bocekcik komutuyla ). Sınıf yükleyici (Class Loader) Bocekcik.class fiziksel dosyasını bulmaya çalışır. Eger bulursa bu sınıf yüklenir, Bocekcik sınıfının bulunduğunu farzedelim , Bu yükleme esnasında Bocekcik sınıfın türetildiği ortaya çıkar ( Bocekcik extends Bocek) . Kalıtım kavramından dolayı Bocek sınıfıda , sınıf yükleyicisi tarafıdan yüklenir (eğer Bocek sınıfıda türetilmiş olsaydi , türetildiği sınıfda yüklenecekti , bu böyle sürüp gidebilir…).

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.
static Bocek.x1 ilk deger verildi
static Bocekcik.x2 ilk deger verildi
Sırada main() metodunun çağrılmasına gelmiştir . Ekrana çıkan üçüncü satır ;
Bocekcik - basla..
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
a = 10, b = 0

Son olarak Bocekcik sınıfının içersindeki statik olmayan( non-static) değişkenlere ilk değerleri verilir ve Bocecik sınıfının yapılandırıcısı çağrılır.
Bocekcik.k ilk deger verildi
k = 18
b = 17


ve mutlu son …

Yorumlar

Bu blogdaki popüler yayınlar

Soru ve Cevaplarla Kompanzasyon

Aktif Güç Nedir,Reaktif Güç Nedir

Sinusoidal AC dalga şekli, Tepe, ortalama, efektif(rms), değer tanımları...