Bir Arayüzde tanımlanan yöntemin "varsayılan" uygulaması nedir?


91

Koleksiyon Arayüzünde removeIf(), uygulamasını içeren adlı bir yöntem buldum .

default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);  
    boolean removed = false;  
    final Iterator<E> each = iterator();   
    while (each.hasNext()) {  
        if (filter.test(each.next())) {  
            each.remove();  
            removed = true;  
        }  
    }  
    return removed;  
}  

Bir arayüzde yöntem gövdesini tanımlamanın herhangi bir yolu olup olmadığını bilmek istiyorum. Anahtar kelime
nedir defaultve nasıl çalışır?



Yanıtlar:


162

Gönderen https://dzone.com/articles/interface-default-methods-java

Java 8, geliştiricinin bu arabirimin mevcut uygulamasını bozmadan arabirimlere yeni yöntemler eklemesine izin veren "Varsayılan Yöntem" veya (Savunma yöntemleri) yeni özelliği sunar. Somut bir sınıfın o yöntem için bir uygulama sağlayamaması durumunda varsayılan olarak kullanılacak arayüz tanımlama uygulamasına izin vermek için esneklik sağlar.

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}

public class ClassAB implements A {
}

İnsanların yeni özelliği ilk kez duyduklarında varsayılan yöntemler hakkında sordukları ortak bir soru var:

Ya sınıf iki arabirim uygularsa ve bu arabirimlerin ikisi de aynı imzaya sahip varsayılan bir yöntemi tanımlarsa?

Bu durumu açıklamak için örnek:

public interface A {  
    default void foo(){  
        System.out.println("Calling A.foo()");  
    }  
}

public interface B {
    default void foo(){
        System.out.println("Calling B.foo()");
    }
}


public class ClassAB implements A, B {

}  

Bu kod aşağıdaki sonuçla derlenemez:

java: class Clazz inherits unrelated defaults for foo() from types A and B

Bunu düzeltmek için, Clazz'da, çakışan yöntemi geçersiz kılarak manuel olarak çözmemiz gerekir:

public class Clazz implements A, B {
    public void foo(){}
}

Ama ya kendi yöntemimizi uygulamak yerine A arabiriminden foo () yönteminin varsayılan uygulamasını çağırmak istersek ne olur?

A # foo () 'ya şu şekilde başvurmak mümkündür:

public class Clazz implements A, B {
    public void foo(){
       A.super.foo();
    }
}

19
Teşekkürler, gerçekten güzel bir sergi. Ben sormaya fırsat bulamadan tüm sorularımı cevapladın.
Jeff Hutchins

neden bunun yerine soyut kullanmıyorsunuz?
Astolfo Hoscher

1
@AstolfoHoscher Yalnızca bir sınıfı genişletebilirsiniz, ancak birden çok arabirim uygulayabilirsiniz.
Charles Wood

49

Bu yöntemlere varsayılan yöntemler denir. Varsayılan yöntem veya Defender yöntemi , Java 8'e yeni eklenen özelliklerden biridir.

Bir arabirim yönteminin, somut bir sınıfın o yöntem için bir uygulama sağlamaması durumunda varsayılan olarak kullanılan bir uygulama sağlamasına izin vermek için kullanılacaktır.

Öyleyse, varsayılan bir yöntemle bir arayüzünüz varsa:

public interface Hello {
    default void sayHello() {
        System.out.println("Hello");
    }
}

Aşağıdaki sınıf tamamen geçerlidir:

public class HelloImpl implements Hello {

}

Şunun bir örneğini oluşturursanız HelloImpl:

Hello hello = new HelloImpl();
hello.sayHello();  // This will invoke the default method in interface

Kullanışlı bağlantılar:


Öyleyse, bir sınıf bir arabirim uygularsa ve yöntemini uygulamazsa sorun olur mu? Java7 söz konusu olduğunda, benim kullandığım buna izin verilmiyor.
Aniket Thakur

2
@AniketThakur. Buna Java 8'den önce izin verilmez. Bu özellik yalnızca Java 8'de eklenmiştir. Uygulama sınıfınızda varsayılan yöntemlerin uygulanmasını vermekten kaçınabilirsiniz .
Rohit Jain

1
@PawanMishra. Önceki yorumuma bakın. Hayır, sınıfın uygulanmasında varsayılan arabirim yöntemlerinin uygulanmasını sağlamanıza gerek yoktur.
Rohit Jain

1
@PawanMishra yine de geçersiz kılabilirsiniz. Yalnızca varsayılan uygulamayı kullanmanız gerektiği gibi bir kısıtlama yoktur.
Aniket Thakur

4
Birden fazla mirasın kafasını karıştırmaktan kaçınacak bir ileri adım!
Xtreme Biker

17

Biraz araştırma yaptım ve aşağıdakileri buldum. Bu yardımcı olur umarım.

Mevcut sorun

Normal arabirim yöntemleri soyut olarak bildirilir ve arabirimi uygulayan sınıfta tanımlanmalıdır. Bu, beyan edilen her yöntemi uygulama sorumluluğu ile sınıf uygulayıcısına yük getirir. Daha da önemlisi, bu aynı zamanda bir arayüzün 'yayınlandıktan' sonra genişletilmesinin mümkün olmadığı anlamına gelir. Aksi takdirde, tüm uygulayıcılar uygulamalarını geriye dönük kaynağı ve ikili uyumluluğu bozarak uyarlamalıdır.

Java 8'de benimsenen çözüm

Bu sorunların üstesinden gelmek için, JDK 8'in yeni özelliklerinden biri, mevcut arayüzleri varsayılan yöntemlerle genişletme olanağıdır. Varsayılan yöntemler yalnızca bildirilmez, aynı zamanda arayüzde de tanımlanır.

Dikkat edilmesi gereken önemli noktalar

  1. Uygulayıcılar, sınıfın uygulanmasında varsayılan yöntemleri uygulamamayı seçebilirler.
  2. Uygulayıcılar yine de varsayılan yöntemleri geçersiz kılabilir, örneğin normal son olmayan sınıf yöntemleri alt sınıflarda geçersiz kılınabilir.
  3. Soyut sınıflar, varsayılan yöntemleri soyut olarak (yeniden) bildirebilir ve alt sınıfları yöntemi yeniden uygulamaya zorlayabilir (bazen 'yeniden soyutlama' olarak adlandırılır).
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.