Java kütüphaneleri çok sayıda notasyon (annotation) barındırırlar. Çoğu programcı için bunların en önemlisi @Override
notasyonudur. Sadece metot tanımlarında kullanılabilen bu notasyon metodun kalıttığı sınıf veya uyguladığı arayüzdeki başka bir metodu geçersiz kıldığını belirtir. Bu notasyonu düzenli olarak kullandığınız taktirde sizi birçok hatadan koruyacaktır. Şimdi harf ikililerini ifade etmek için yazılmış aşağıdaki Bigram
sınıfına bakalım:
// Hatayı bulabilir misiniz?
public class Bigram {
private final char first;
private final char second;
public Bigram(char first, char second) {
this.first = first;
this.second = second;
}
public boolean equals(Bigram b) {
return b.first == first && b.second == second;
}
public int hashCode() {
return 31 * first + second;
}
public static void main(String[] args) {
Set<Bigram> s = new HashSet<>();
for (int i = 0; i < 10; i++) {
for (char ch = 'a'; ch <= 'z'; ch++) {
s.add(new Bigram(ch, ch));
}
}
System.out.println(s.size());
}
}
Program main
metodunda yirmi altı tane harf ikilisini "aa", "bb", "cc" .... "zz"
olacak şekilde on kere üst üste bir kümeye (HashSet
) eklemekte ve sonra da bu kümenin kaç elemanlı olduğunu yazdırmaktadır. HashSet
aynı elemanı en fazla bir kez eklememize izin verdiği için sonucun 26
çıkmasını bekleyebilirsiniz ama 260
çıkacaktır. Peki sorun nerede?
Halbuki sınıfı yazan kişi equals
metodunu geçersiz kılmak istemiş (Madde 10) ve hatta hashCode
‘u da geçersiz kılması gerektiğini unutmamış (Madde 11). Ancak, equals
metodunu geçersiz kılmaya çalışan programcı yanlışlıkla aşırı yükleme (overloading) yapmıştır çünkü Object
sınıfından gelen equals
parametre türü olarak Object
beklerken Bigram
sınıfındaki equals
metodunda Object
yerine Bigram
parametresi kullanılmıştır. Bu sebeple de Object
sınıfındaki equals
metodu Bigram
tarafından kalıtılacak ve nesne karşılaştırması için kullanılacaktır. Aynı harf ikililerini ifade eden Bigram
nesneleri kalıtılan equals
için eşit değildir çünkü farklı nesneleri temsil etmektedirler. Bu sebeple de HashSet
içine 26
değil 260
eleman eklenecektir.
Neyse ki bu gibi problemlerin önüne geçmek için çok kolay bir yol var. @Override
notasyonunu kullandığımız zaman derleyiciye üst türde tanımlı bir metodu geçersiz kılmak istediğimizi bildirmiş oluyoruz. Bu sayede derleyici bizim için gerekli kontrolleri yapacaktır ve üst türde geçerli kılmaya müsait bir metot yoksa hata verecektir. Şimdi bunu Bigram
sınıfındaki equals
metodunda nasıl kullanırız onu görelim:
@Override
public boolean equals(Bigram b) {
return b.first == first && b.second == second;
}
Bu notasyonu kullandığımızda sınıfı derlemeye çalışırsak aşağıdaki gibi bir hatayla karşılaşırız:
Bigram.java:10: method does not override or implement a method from a supertype @Override public boolean equals(Bigram b) { ^
Bu hatayı görünce nerede hata yaptığınızı hemen anlayacaksınız, alnınıza vurup aşağıdaki şekilde düzelteceksiniz:
@Override
public boolean equals(Object o) {
if (!(o instanceof Bigram)) {
return false;
}
Bigram b = (Bigram) o;
return b.first == first && b.second == second;
}
Bu sebeple, üst sınıflarda tanımlı bir metodu geçersiz kılmak istediğiniz her durumda Override
notasyonunu kullanmalısınız.
Modern IDE’lerin hemen hepsi geçersiz kılınan metotlara bu notasyonu otomatik olarak ekleyecek şekilde ayarlanabilir. Hatta Override
notasyonunu kullanmayı unuttuğunuz durumlarda sizi eklemeniz için uyarabilirler. Düzenli kullandığınız durumda bu uyarılar sizi istemsiz geçersiz kılma durumlarına karşı da korurlar. Üst türde tanımlı olduğunu bilmediğiniz aynı imzaya sahip bir metot yazacak olursanız, IDE uyarısı sayesinde bunu farkedip durumu düzeltebilirsiniz.
Override
notasyonu hem arayüzlerden gelen hem de üst sınıflardan kalıtılan metotları geçersiz kılmak için kullanılabilir. Varsayılan metotların (default method) dile eklenmesi ile arayüzü uygulayan sınıflarda doğru metot imzalarının kullanıldığından emin olmak için bu notasyonun kullanılması yine önerilir. Ancak arayüz sizin kontrolünüzde ise ve varsayılan metot olmadığını biliyorsanız, uygulayan sınıfta arayüz metotlarını geçersiz kılarken Override
notasyonunu kullanmamayı seçebilirsiniz.
Soyut sınıflar ve arayüzler yazarken ise bir üst sınıf veya başka bir arayüzden gelen metodları geçersiz kılmak istediğiniz durumlarda Override
notasyonunu kullanmak iyi bir fikir olacaktır. Örneğin, Set
arayüzü Collection
arayüzünü kalıtır ama yeni bir metot eklemez. Bu sebeple Collection
arayüzüne yanlışlıkla yeni bir metot eklememek için bütün metot tanımlarında Override
notasyonunu kullanması mantıklı olacaktır.
Özetle, Override
notasyonu kullanıldığı zaman derleyici sizi türlü hatalardan korur. Bu notasyonu üst türlerdeki metotları geçersiz kılmak istediğiniz durumlarda kullanın. Somut sınıflarda soyut metotları geçersiz kılıyorsanız kullanmanız şart değildir ancak bir zararı da yoktur.