Last updated on January 7, 2015
Java dilinde detayları çok iyi bilinmeyen ve belki de pek önemsenmeyen, kıyıda köşede kalmış konulardan birisi de “final” anahtar kelimesidir. Değişkenlere, metodlara ve hatta sınıflara uygulanabilen, kullanıldığı zaman çok faydalı olabilecek bu anahtar kelimenin bütün kullanım detaylarını bu yazıda açıklamaya çalışacağım.
Final değişkenler
Öncelikle değişkenlerden başlayalım. Final olarak tanımlanan değişkenler ilk değerlerini aldıktan sonra değiştirilemezler. Bununla birlikte final değişkenlere ilk değer ataması ya tanımlandığı satırda ya da yapıcı metot içerisinde yapılmalıdır. Bunun anlamı şudur: nesnenin yaratılması işi bittiğinde final değişkenimizin değeri belli olacaktır ve bir daha değiştirilemeyecektir. Bunu şöyle bir örnekle açıklayalım:
public class FinalDeneme { private final int finalDegisken; public void printFinal() { System.out.println("Final Degisken Degeri: " + finalDegisken); } }
Java’da ilkel türde (primitive) olarak tanımlanan değişkenlere ilk değer ataması yapılmadığı zaman otomatik olarak ön tanımlı değerler atanır. Örneğin int türünde bir değişken tanımladığımız zaman ilk değer ataması yapmadıysak bu değişkenin değeri otomatik olarak 0 olacaktır. Ancak final değişkenler için bu durum farklıdır. İlk değer atamasını değişkeni tanımladığımız satırda veya yapıcı metod içerisinde mutlaka yapmamız gerekmektedir. Yukarıdaki kod örneğinde final değişken tanımlanmış ancak ilk değer ataması yapılmamıştır. Bu durumda derleme anında aşağıdaki gibi bir hata ile karşılaşırız.
The blank final field finalDegisken may not have been initialized
Derleyicinin verdiği hata final değişkenimize ilk değer ataması yapmadığımızı göstermektedir. Bu hatayı ortadan kaldırmak için değişkenimize ilk değer ataması yaparak kodumuzu tekrar derleyelim.
public class FinalDeneme { private final int finalDegisken; public void printFinal() { finalDegisken = 5; System.out.println("Final Degisken Degeri: " + finalDegisken); } }
Kodu yukarıdaki gibi değiştirerek tekrar derlemeye çalıştığımızda yine aynı hata ile karşılaşırız. Çünkü daha önce de belirttiğim gibi final değişkenlere ilk değer atamaları ya değişkenin tanımlandığı satırda ya da yapıcı metod içerisinde olmalıdır. Burada ilk değer ataması sınıfın içerisinde herhangi bir metod içerisinde yapılmıştır. Şimdi bu kurala uygun bir kod yazıp aynı işlemi tekrarlayalım.
public class FinalDeneme { private final int finalDegisken; public FinalDeneme(int deger) { finalDegisken = deger; } public void printFinal() { System.out.println("Final Degisken Degeri: " + finalDegisken); } }
Kodu yukarıdaki şekilde yazdığımızda hatasız derlenecektir çünkü final değişkenin değeri yapıcı metod içerisinde belirlenmiştir. Aşağıdaki gibi bir sınıf yardımıyla rastgele bir tamsayı değeri üretip kodun çalışıp çalışmadığını test edebiliriz.
import java.util.Random; public class Client { public static void main(String[] args) { FinalDeneme finalDeneme = new FinalDeneme(new Random().nextInt()); finalDeneme.printFinal(); } }
Kod çalıştırıldığında rastgele üretilen tamsayı değeri yapıcı metod içerisinde final değişkene atanacak ve ekrana bastırılacaktır. Bu şekilde yapıcı metod içerisinde final değişkenlere değer atanabileceği gibi değişkenin tanımlandığı satırda da ilk değer atanabilir.
Final değişkenlerin değerleri ilk değer ataması yapıldıktan sonra değiştirilemez. Zaten final değişkenlerin kullanım alanı da budur. Değerinin değişmesini istemediğimiz bir değiikeni final anahtar kelimesi ile tanımlarız. Aşağıda bu kuralı ihlal eden bir kod örneği görülmektedir.
public class FinalDeneme { private final int finalDegisken; public FinalDeneme(int deger) { finalDegisken = deger; } public void printFinal() { finalDegisken = 5; System.out.println("Final Degisken Degeri: " + finalDegisken); } }
Yukarıdaki kodda final olarak tanımlanmış değişkene yapıcı metod içerisinde ilk değer atadıktan sonra printFinal() metodu içerisinde değiştirmeye çalışıyoruz. Bu durum derleme anında aşağıdaki gibi bir hataya yol açacaktır.
The final field FinalDeneme.finalDegisken cannot be assigned
Final değişkenlerin değiştirilememesi kuralı referans türündeki değişkenler için de geçerlidir. Final anahtar kelimesi ile bir liste referansı oluşturduğumuzu düşünelim. Bu durumda listenin içeriğini istediğimiz gibi değiştirme şansımız olmasına karşın final referans ile başka bir liste tutma şansımız kalmaz. Bu durumu aşağıdaki gibi örnekleyebiliriz.
import java.util.ArrayList; import java.util.List; import java.util.Random; public class FinalDeneme { private final List finalListe = new ArrayList(); public FinalDeneme() { Random random = new Random(); for(int i = 0; i < 5; i++) finalListe.add(random.nextInt(100)); } public void printFinal() { System.out.println("Final Liste"); for(Integer deger : finalListe) System.out.println(deger); } } public class Client { public static void main(String[] args) { FinalDeneme finalDeneme = new FinalDeneme(); finalDeneme.printFinal(); } }
Yukarıdaki sınıflar doğru bir şekilde derlenecektir ve çalıştırıldığında final referans ile tutulan liste nesnesine 0 ile 99 arasında 5 tane rastgele değer eklenecek ve ardından ekrana basılacaktır. Yani final referans ile tuttuğumuz nesne üzerinde değişiklikler yapmak mümkündür ancak final referansın tuttuğu nesneyi değiştirmeye çalışmak hataya yol açacaktır. Aşağıdaki kodu inceleyelim.
import java.util.ArrayList; import java.util.List; import java.util.Random; public class FinalDeneme { private final List finalListe = new ArrayList(); public FinalDeneme() { finalListe = new ArrayList(); Random random = new Random(); for(int i = 0; i < 5; i++) finalListe.add(random.nextInt(100)); } }
Yukarıdaki kodda görüldüğü gibi final nitelikli liste referansını tanımlarken bir liste zaten oluşturduk. Daha sonra yapıcı metod içerisinde yeniden başka bir liste nesnesini aynı final referansa atamaya çalışıyoruz. Final referansların tutacağı nesneler bir kere tanımlandıktan sonra değiştirilemeyeceği için kod derleme aşamasından geçemeyecektir.
Final değişkenleri metodlar içerisinde lokal olarak tanımlamak da mümkündür. Bu durumda final değişkene ilk değeri tanımlama esnasında ya da metodun içerisinde herhangi bir yerde vermek mümkün olur. Ancak yine verilen ilk değeri değiştirmek mümkün olmaz. Aşağıdaki metodu inceleyelim.
public void finalDenemeMetod() { final int finalLokalDegisken; System.out.println("Bla bla bla"); finalLokalDegisken = 5; }
Yukarıdaki metod hatasız derlenecektir. Metod içerisinde tanımlanan final değişkenlere metod içerisinde herhangi bir yerde tek bir defa atama yapılabilir. İlk atamadan sonra final değişken üzerinde değişiklik yapılamaz.
Final değişkenlere verilebilecek son örnek sabit tanımlamaktır. Final ile static anahtar kelimesini birlikte kullanarak sabit tanımlamak mümkündür. Değerlerini önceden bildiğimiz ve değişmesini istemediğimiz değişkenleri sabit olarak tanımlayıp kullanabiliriz.
public class Constants { public static final int MAX_LENGTH = 100; public static final int MIN_LENGTH = 5; }
Yukarıdaki gibi bütün sınıfların ortak olarak kullanabileceği sabit değişkenler tanımlayabiliriz. Sabitler okunabilirliği artırmak amacıyla büyük harflerle tanımlanırlar. Static anahtar kelimesi hakkında daha fazla bilgi almak için bu adresteki yazımı okuyabilirsiniz.
Final Metodlar
Final anahtar kelimesi metodlara da uygulanabilmektedir. Final belirteci ile yazılan metodlar alt sınıflar tarafından override edilemezler. Aşağıdaki kod bu durumu örneklemektedir.
public class FinalDeneme { public final void finalMetod() { System.out.println("Ata sınıftaki finalMetod"); } } public class FinalDenemeSubClass extends FinalDeneme { public void finalMetod() { System.out.println("Alt sınıftaki finalMetod"); } }
Yukarıdaki kod derleme aşamasında aşağıdaki hatayı üretecektir.
Cannot override the final method from FinalDeneme
Görüldüğü gibi ata sınıfta final belirteci ile tanımladığımız bir metodu alt sınıfta override etmeye çalıştığımızda hata alıyoruz. Alt sınıflarda override edilerek değiştirilmesini istemediğimiz metodları final olarak tanımlayabiliriz.
Final Sınıflar
Final anahtar kelimesi sınıflara da uygulanabilmektedir. Bir sınıf aşağıdaki gibi final anahtar kelimesi kullanılarak tanımlanıyorsa bu sınıfı kalıtmak mümkün olmaz. Aşağıdaki kodu inceleyelim.
public final class FinalDeneme { public void metod() { System.out.println("Ata sınıftaki finalMetod"); } } public class FinalDenemeSubClass extends FinalDeneme { public void metod() { System.out.println("Alt sınıftaki finalMetod"); } }
Bu örnekte final tanımlanmış bir sınıfı kalıtıp içerisindeki metodu alt sınıf içerisinde override etmeye çalışıyoruz. Metod final olarak tanımlanmadığı için metodun override edilmesi aslında mümkün gibi görünüyor ancak bu sefer sınıfı final olarak tanımladığımız için sınıfı kalıtmak mümkün olmamaktadır. Çünkü final olarak tanımlanan sınıfları hiçbir sınıf kalıtamaz. Dolayısıyla yukarıdaki kod da aşağıdaki gibi bir hataya yol açacaktır.
The type FinalDenemeSubClass cannot subclass the final class FinalDeneme
Final Parametreler
Final anahtar kelimesinin bir başka kullanım alanı da metod parametleridir. Metod içerisinde değiştirilmesini istemediğimiz parametreleri final anahtar kelimesi ile tanımlayabiliriz. Aşağıdaki kod bunu anlamamıza yardımcı olacaktır.
public final class FinalDeneme { public void metod1() { int a = 4; System.out.println("a'nin degeri: " + a); metod2(a); System.out.println("a'nin degeri: " + a); } public void metod2(final int b) { b = b*2; } }
Yukarıdaki kodda metod1 içerisinde tanımladığımız “a” değişkenini parametre olarak metod2’ye aktarıyoruz ve metod2 içerisinde parametre değişkeninin değerini değiştirmeye çalışıyoruz. Parametre değişkeni “b” final olarak tanımlandığı için b değişkenine metod2 içerisinde herhangi bir atama yapmak mümkün değildir. Bu değişken metod2 içerisinde sadece okunabilir, üzerinde yazma yapılamaz. Bu sebeple yukarıdaki kod derleme aşamasından geçemeyecek ve aşağıdaki hatayı üretecektir.
The final local variable b cannot be assigned. It must be blank and not using a compound assignment
Son Notlar
Yazıda final anahtar kelimesinin bütün kullanım alanlarını elimden geldiğince açıklamaya çalıştım. Ek bir iki bilgi daha vermek gerekirse final değişkenler iş parçacıklarının (thread) kullanıldığı programlarda senkronizasyonu sağlamada bizlere yardımcı olurlar. Bunun yanında yazı boyunca değiştirilemez dediğimiz final değişkenler aslında Java’daki reflection mekanizması sayesinde çalışma zamanında (runtime) değiştirilebilirler. Bunlar tabii ki başka yazıların konuları olabilir. Bu yazı da zaten fazlasıyla uzun oldu, sonraki yazılarda görüşmek üzere..
Selamlar, yazinizi okudum, cok aciklayici buldum, emeginize saglik. Benim bir sorum olacak. Ben bir static final String accountNr; olusturmak istiyorum ve degerini olusturdugum bir yapilandirici icinde atamayi düsünüyorum. Ama tabiki bu mümkün degil. Nedeni; yapilandiricilar static olamiyor ve accountNr degiskenim static oldugu icin herhangi bir deger yapilandirici icinde atanamiyor. Söyle ki ;
class Account{
private static final String accountNr;
Account(String accountNr){
this.accountNr=accountNr;
}
}
accountNr; static ve final olmak zorunda. Baska türlü nasil yeni deger atayabilirim? ENUM ile ilgisi var mi=? Yardimci olabilirseniz sevinirim.
Iyi günler.
Merhaba,
Statik kod blokları ile bu istediğini yapabilirsin. Aşağıdaki gibi bir kod işini görecektir.
public static final String accountNr;
static {
accountNr = “asdf”;
}
Statik kod bloklarından aşağıda linkini verdiğim yazıda bahsetmiştim. İstersen bakabilirsin. Kolay gelsin..
https://www.seckintozlu.com/307-javada-static-anahtar-kelimesi-ve-kullanimi.html
static yazısınıda final yazınızı da okudum gerçekten çok iyi anlatış biçiminiz var tebrik ederim.
Çok sade ve anlaşılır. Çok teşekkürler.. Keşke bütün dökümanların üslubu sizinki gibi olsa 🙂
Emeğinize sağlık çok güzel bir anlatım sunmuşsunuz. Teşekkürler
Helal olsun çok güzel bir makale olmuş elinize sağlık.
Ellerinize sağlık çok faydalı bir makale. Yazılımcılar IDE’lerin kendilerini uyarmaları üzerine değişkenlerini, metotlarını final yaparak değiştiriyorlar ancak bunu anlayarak yapmak çok önemli ve bu makale de öğrenmek için hazırlanmış çok güzel bir makale.
Elinize saglık, fazlasıyla açıklayıcı. Çok faydalı oldu vize öncesi
Emeğine Sağlık kardeşim gayet güzel bir dille yazmışsın
hocam merhaba, javayı öğrendiğim şu günlerde aradığım kaynaklar arasında en doğru ve düzgün anlatan senin yazını buldum. Gerçekten teşekkür ederim okadar soru işareti vardı ki kafamda hepsi netleşti sayende açık kapı bırakmadın 🙂
Yazılarını kesme nolur, artık takibimdesin.
Gerçekten takdir edilecek kadar güzel anlatıyorsunuz…
Allah’sizin gibi bilgi paylaşanların bilgisini ve emsalini arttırsın .
Emeginiz icin tesekkür ederim fakat yazdiklarinizda ciddi manada hatalar var. Java’daki final anahtar kelimesinin, referans oldugu nesnenin icindeki degerle hicbir alakasi yoktur. Final anahtar kelimesi sadece ve sadece, referansin degisip degismedigini kontrol eder. Yani, final ile tanimlanmis bir degiskenin referansini degistirmeden, icindeki degeri istediniz kadar degistirebilirsiniz.
Dediginiz dogru tabiki ama yazida ben zaten onu anlatiyorum. Ciddi manada hatalar var demissiniz ornek gosterebilir misiniz? Liste kullanarak ornek verdigim bolumleri okuyun lutfen uzun uzun referanslari anlatiyorum.