Java - Interface - 2

Java - Interface - 2

Arkadaşlar merhaba java'da ınterface yazımıza devam ediyoruz.

Default Method

Default method, bir interface'de default anahtar sözcükle tanımlanan bir method'dur ve bir method gövdesi içerir.

Default bir method, interface'yi implement eden bir sınıf tarafından override edilebilir.

Default adı, default bir implementation'a sahip abstract interface method olarak görüldüğü kavramından gelir. Sınıf, default methodu override etme seçeneğine sahiptir, ancak yoksa, varsayılan implementation kullanılacaktır.

Default Method Amacı

Java diline default methodlar eklemek için amaç, geriye dönük uyumluluk içindi.Default method, interface'yi uygulayan eski kodu değiştirmeye gerek kalmadan mevcut bir interfaceye yeni bir method eklemenize olanak tanır.

Java'ya default methodlar eklemek için başka bir amaç da kolaylık sağlamak içindir. Örneğin, Comparator interface'si, ters sırada yeni bir Comparator döndüren default bir reversed() methodu içerir.

Bunlar, arabirimi uygulayan her sınıfta yazılabilirken, interfacede default bir method olarak tanımlanmış olması oldukça yararlıdır.

public interface Temperature {

    boolean isItHot();

    default double getTemperature() {
        return 10.0;
    }
}

Biri abstract isItHot() methodu, diğeri ise default getTemperature() methodudur.

Temperature implement eden herhangi bir sınıf getTemperature() methodunun default uygulamasına güvenebilir veya methodu override edebilir.

Bu methodların her ikiside örtük(implicit) public değiştiriciyi içerir.Bu neden bunların farklı bir erişim değiştirici ile override edilmesine izin verilmez.

public class CalculateTemperature implements Temperature{

    private static int degree = 2;

    @Override
    public boolean isItHot() {
        return false;
    }

    @Override
    public double getTemperature() {
        return 12.0 * degree;
    }
}

Default Interface Methodları Tanımlama Kuralları

  • Default bir method yalnızca bir arabirim(interface) içinde bildirilebilir.

  • Default bir method, default anahtar sözcükle işaretlenmeli ve bir method gövdesi içermelidir.

  • Default bir methodun public olduğu varsayılır.

  • Default method abstract, final ve static olamaz.

  • Default bir method, interfaceyi implement eden bir sınıf tarafından override edilebilir.

  • Bir sınıf, aynı method imzası ile iki veya daha fazla default methodu miras alırsa, sınıfın methodu override etmesi gerekir.

  • Soyut methodlardan farklı olarak, default interface methodları abstract olarak işaretlenemez ve bir gövde sağlamalıdır.

  • Ayrıca, interface'yi uygulayan sınıflarda her zaman override edinilebildikleri için final olarak işaretlenemezler.

  • Son olarak, interface'yi uygulayan sınıfın instance'ı ile ilişkilendirildikleri için statik olarak işaretlenemezler.

Yinelenen Default Methodlar Devralma

public interface Walk {
    public default int getSpeed() { return 5; }
}
public interface Run {
    public default int getSpeed() { return 10; }
}
public class Cat implements Walk, Run { // DOES NOT COMPILE
    public static void main(String[] args) {
        System.out.println(new Cat().getSpeed());
    }
}

Bu örnekte Cat, getSpeed() için iki default methodu devralır, peki hangisini kullanır ?

Walk ve Run, Cat sınıfında nasıl kullanıldığına göre kodun 5 mi yoksa 10 mu çıkması gerektiği net değil.Bu durumda derleme başarısız olur.

Bir sınıf, aynı method imzasına sahip default methodlara sahip iki interface uygularsa, derleyici bir hata bildirir. Bu kural, soyut sınıflar çin bile geçerlidir, çünkü yinelenen method, soyut sınıf içindeki somut bir method içinde çağrılabilir.

Interface'yi uygulayan sınıf, yinelenen default methodu override ederse, kod sorunsuz bir şekilde derlenir.

Çakışan methodu override ederek, methodun hangi sürümünün çağrılacağı konusundaki belirsizlik ortadan kaldırılır. Örneğin, aşağıdaki değiştirilmiş Cat uygulaması derlenecek ve 1 çıktısı alacaktır.

public class Cat implements Walk, Run { 
    public static void main(String[] args) {
        System.out.println(new Cat().getSpeed());
        System.out.println(new Cat().getWalkSpeed());
    }

  public int getSpeed() {
        return 1;
    }

    public int getWalkSpeed() {
        return Walk.super.getSpeed();
    }

}

Walk.getSpeed()'i şeklinde çağıramazsınız. Default bir method, override edilebildikleri için instance'ın bir parçası olarak kabul edilir, bu nedenle statik bir method gibi çağrılamazlar.

public int getWalkSpeed() {
        return Walk.super.getSpeed();
    }

Bu örnekte, önce interface adını, ardından super anahtar sözcüğünü, ardından çağırmak istediğimiz default methodu kullanıyoruz.Ayrıca, main() methodunda super öğesine erişilemediği için, çağrıyı devralınan default methoda getWalkSpeed() instance methodunun içine koyarız.

Static Interface Methodları

Statik method tanımlama kuralları şu şekildedir;

  • Static olarak işaretlenmek zorunda ve method gövdesi olmak zorundadır.

  • Access modifiers'ı olmayan static bir method public sayılır.

  • Abstract veya final olamaz.

  • Statik bir method miras alınmaz ve interface adına referans yapılmadan interfaceyi implement eden bir sınıfta erişilemez.

  • private erişim belirteci statik methodlar ile kullanılabilir.

public interface Hop {
   static int getJumpHeight() {
      return 4;
  }
}

getJumpHeight()methodu, bir sınıfta tanımlanan statik bir method gibi çalışır.Başka bir deyişle, Hop.getJumpHeight() sözdizimi kullanılarak bir sınıf instance'si olmadan erişilebilir.

Method bir erişim değiştiricisi olmadan tanımlandığından, derleyici public erişim değiştiricisini otomatik olarak ekleyecektir.

public class Kangaroo implements Hop{

    public void print(){

       System.out.println(getJumpHeight()); // DOES NOT COMPILE

       System.out.println(Hop.getJumpHeight());
    }
}

Interface adı ile birlikte açıkca bir referans olmadan, Kangaroo Hop'u uygulasa bile kod derlenmeyecektir.

Bu şekilde, statik interface methodları, methodun bir üst sınıfta tanımlanmış olması durumunda olduğu gibi interfaceyi implement eden bir sınıf tarafından miras alınmaz.

Statik methodlar sınıfın bir örneği(instance) gerektirmediğinden interface adı kullanılarak ve public statik methodu çağırarak sorun kolayca çözülebilir.

Java, statik interface methodlarının çoklu kalıtım sorununu, bunların devralınmasına izin vermeyerek "çözdü". Bu, interfaceyi uygulayan hem alt interfaceler hem de sınıflar için geçerlidir.

Örneğin, aynı imzaya sahip statik methodlar içeren iki interfaceyi uygulayan bir sınıf yine de derlenecektir.

Private Interface Method

Private bir interface methodu, private değiştiriciyle işaretlenmeli ve bir method gövdesi içermelidir.

Private bir interface methodu , interface tanımı içinde yalnızca default ve private (statik olmayan) methodlar ile çağrılabilir.

Private interface methodları, bir sınıf içindeki instance methodlara çok benzer. Bir sınıftaki private methodlar gibi, kalıtsal olmadıkları için abstract olarak bildirilemezler.

Private oldukları için interface dışında kullanılamazlar.

Örneğin, bir dizi default metoda sahip bir Working interfacemiz olduğunu varsayalım.

Her default methodda, bazı değerleri kontrol etmek ve bazı bilgilere göre saatlik ücret hesaplamak istiyoruz.

Aynı kodu kopyalayıp her methoda yapıştırabiliriz veya private bir interface methodu kullanabiliriz.

public interface Working {

   default void startTime() {
       checkTime(8);
   }

   default void endTime(){
       checkTime(18);
   }

   private void checkTime(int hour){
       if (hour > 8){
           System.out.println("You will charge extra");
       }else {
           System.out.println("You will receive standard fare");
       }
   }
}

Private Static Interface Methodları

Private interface methodlarını yanı sıra Java 9, private statik interface methodlarını ekledi. Tahmin edebileceğiniz gibi, private statik interface methodlarının amacı,interface bildiriminde statik methodlarda kod tekrarını azaltmaktır.

Ayrıca, instance methodları bir sınıf içindeki statik methodlara erişebildiğinden,bunlara default ve private methodlar da erişilebilir.

Tanımlama kurallar şu şekildedir;

  • Private bir statik method, private ve statik değiştiricilerle işaretlenmeli ve bir method gövdesi içermelidir.

  • Private statik interface methodu, yalnızca interface tanımındaki diğer methodlar tarafından çağrılabilir.

  • Hem private hem de private statik methodlar, default ve private methodlardan çağrılabilir. Bu, bir instance methodun hem statik hem de instance methodları nasıl çağırabildiğine eşdeğerdir.

  • Öte yandan, private bir statik method'dan private bir method çağrılamaz.

  • Bu, bir sınıftaki statik bir methoddan bir instance method'a erişmeye çalışmak gibidir.

public interface Swim {

    private static void breathe(String type) {
        System.out.println("Inhale");
        System.out.println("\"Performing stroke: \" + type");
        System.out.println("Exhale");
    }

    static void butterFly() {
        breathe("butterfly");
    }

    public static void freestyle() {
        breathe("freestyle");
    }

    default void backstroke() {
        breathe("backstroke");
    }

    private void breaststroke() {
        breathe("breaststroke");
    }

}

NEDEN KULLANILIR ?

Cevap, kapsüllemeyi iyileştirmektir, çünkü bu methodların interface bildiriminin dışında görünmesini istemeyebiliriz. Kapsülleme ve güvenlik en iyi, dışarıdan çağıran kişinin bir sınıfın veya arabirimin dahili uygulaması hakkında mümkün olduğunca az bilgi sahibi olduğu durumlarda çalışır. Private interface methodlarını kullanmak yalnızca kod tekrarını azaltmanın bir yolunu sağlamakla kalmaz, aynı zamanda temeldeki bazı uygulama ayrıntılarını arabirim kullanıcılarından gizlemenin bir yolunu da sağlar.

Umarım faydalı olmuştur.