Jaka jest „domyślna” implementacja metody zdefiniowanej w interfejsie?


91

W interfejsie kolekcji znalazłem metodę o nazwie, removeIf()która zawiera jej implementację.

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;  
}  

Chcę wiedzieć, czy istnieje sposób zdefiniowania treści metody w interfejsie?
Jakie jest defaultsłowo kluczowe i jak działa?



Odpowiedzi:


162

Z https://dzone.com/articles/interface-default-methods-java

Java 8 wprowadza nową funkcję „Metoda domyślna” lub (metody Defendera), która umożliwia programistom dodawanie nowych metod do interfejsów bez przerywania istniejącej implementacji tych interfejsów. Zapewnia elastyczność pozwalającą na definiowanie implementacji interfejsu, która będzie używana jako domyślna w sytuacji, gdy konkretna klasa nie zapewni implementacji dla tej metody.

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

public class ClassAB implements A {
}

Jest jedno częste pytanie, które ludzie pytają o metody domyślne, gdy po raz pierwszy słyszą o nowej funkcji:

Co się stanie, jeśli klasa implementuje dwa interfejsy i oba te interfejsy definiują domyślną metodę z tym samym podpisem?

Przykład ilustrujący tę sytuację:

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 {

}  

Ten kod nie może zostać skompilowany z następującym wynikiem:

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

Aby to naprawić, w Clazz musimy rozwiązać to ręcznie, zastępując metodę powodującą konflikt:

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

Ale co by było, gdybyśmy chcieli wywołać domyślną implementację metody foo () z interfejsu A zamiast implementować naszą własną.

Do A # foo () można odwoływać się w następujący sposób:

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

18
Dzięki, naprawdę dobra ekspozycja. Odpowiedziałeś na wszystkie moje pytania, zanim zdążyłem je zadać.
Jeff Hutchins

dlaczego nie użyć abstrakcji zamiast tego?
Astolfo Hoscher

1
@AstolfoHoscher Możesz rozszerzyć tylko jedną klasę, ale możesz zaimplementować wiele interfejsów.
Charles Wood

49

Te metody nazywane są metodami domyślnymi. Metoda domyślna lub metoda Defender to jedna z nowo dodanych funkcji w Javie 8.

Zostaną one użyte, aby umożliwić metodzie interfejsu zapewnienie implementacji używanej jako domyślna w przypadku, gdy konkretna klasa nie zapewnia implementacji dla tej metody.

Więc jeśli masz interfejs, z domyślną metodą:

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

Następująca klasa jest całkowicie poprawna:

public class HelloImpl implements Hello {

}

Jeśli utworzysz instancję HelloImpl:

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

Przydatne linki:


Czy jest ok, jeśli klasa implementuje interfejs, a nie implementuje swojej metody? Jeśli chodzi o Javę7, której używam, jest to niedozwolone.
Aniket Thakur

2
@AniketThakur. Nie jest to dozwolone przed wersją Java 8. Ta funkcja jest dodawana tylko w języku Java 8. Możesz uniknąć podawania implementacji metod domyślnych w klasie implementującej.
Rohit Jain

1
@PawanMishra. Zobacz mój poprzedni komentarz. Nie, nie musisz zapewniać implementacji domyślnych metod interfejsu w implementacji klasy.
Rohit Jain

1
@PawanMishra możesz to jednak zastąpić. Nie ma ograniczeń, na przykład musisz używać tylko domyślnej implementacji.
Aniket Thakur

4
Krok naprzód, który wreszcie pozwoli uniknąć zdziwienia wielokrotnym dziedziczeniem!
Xtreme Biker

17

Zrobiłem trochę badań i znalazłem następujące. Mam nadzieję że to pomoże.

Istniejący problem

Normalne metody interfejsu są deklarowane jako abstrakcyjne i muszą być zdefiniowane w klasie implementującej interfejs. To „obciąża” osobę implementującą klasę odpowiedzialnością za implementację każdej zadeklarowanej metody. Co ważniejsze, oznacza to również, że rozszerzenie interfejsu nie jest możliwe po „publikacji”. W przeciwnym razie wszyscy implementujący musieliby dostosować swoją implementację, łamiąc wsteczną kompatybilność źródłową i binarną.

Rozwiązanie przyjęte w Javie 8

Aby poradzić sobie z tymi problemami, jedną z nowych funkcji JDK 8 jest możliwość rozszerzenia istniejących interfejsów za pomocą domyślnych metod. Metody domyślne są nie tylko deklarowane, ale także definiowane w interfejsie.

Ważne punkty do zapamiętania

  1. Implementatorzy mogą zdecydować, aby nie implementować metod domyślnych w implementacji klasy.
  2. Implementatorzy mogą nadal przesłonić metody domyślne, na przykład zwykłe metody klas nieostatecznych mogą zostać zastąpione w podklasach.
  3. Klasy abstrakcyjne mogą nawet (ponownie) deklarować metody domyślne jako abstrakcyjne, zmuszając podklasy do ponownego zaimplementowania metody (czasami nazywane „re-abstrakcją”).
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.