Какая реализация метода по умолчанию определена в интерфейсе?

91

В интерфейсе коллекции я нашел метод с именем, removeIf()который содержит его реализацию.

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

Я хочу знать, есть ли способ определить тело метода в интерфейсе?
Что такое defaultключевое слово и как оно работает?

gifpif
источник
3
см. этот пост о стандартном zeroturnaround.com/rebellabs/java-8-explained-default-methods/…
emeraldjava
Связанное сообщение stackoverflow.com/questions/31578427/…
Рави

Ответы:

162

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

В Java 8 представлена ​​новая функция «Метод по умолчанию» или (Методы Защитника), которая позволяет разработчику добавлять новые методы в интерфейсы, не нарушая существующую реализацию этих интерфейсов. Он обеспечивает гибкость, позволяя интерфейсу определять реализацию, которая будет использоваться по умолчанию в ситуации, когда конкретный класс не может предоставить реализацию для этого метода.

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

public class ClassAB implements A {
}

Есть один общий вопрос, который люди задают о методах по умолчанию, когда впервые слышат о новой функции:

Что, если класс реализует два интерфейса, и оба этих интерфейса определяют метод по умолчанию с одинаковой сигнатурой?

Пример, иллюстрирующий эту ситуацию:

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 {

}  

Этот код не компилируется со следующим результатом:

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

Чтобы исправить это, в Clazz мы должны решить это вручную, переопределив конфликтующий метод:

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

Но что, если бы мы хотели вызвать реализацию метода foo () по умолчанию из интерфейса A вместо реализации нашей собственной.

Можно ссылаться на A # foo () следующим образом:

public class Clazz implements A, B {
    public void foo(){
       A.super.foo();
    }
}
gifpif
источник
18
Спасибо, действительно хорошая экспозиция. Вы ответили на все мои вопросы, прежде чем я успел их задать.
Джефф Хатчинс,
почему бы вместо этого не использовать абстрактное?
Астольфо Хошер 04
1
@AstolfoHoscher Вы можете расширить только один класс, но можете реализовать несколько интерфейсов.
Чарльз Вуд
49

Эти методы называются методами по умолчанию. Метод по умолчанию или метод Защитника - одна из недавно добавленных функций в Java 8.

Они будут использоваться, чтобы позволить методу интерфейса предоставлять реализацию, используемую по умолчанию, в случае, если конкретный класс не предоставляет реализацию для этого метода.

Итак, если у вас есть интерфейс с методом по умолчанию:

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

Следующий класс вполне допустим:

public class HelloImpl implements Hello {

}

Если вы создаете экземпляр HelloImpl:

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

Полезные ссылки:

Рохит Джайн
источник
Так нормально, если класс реализует интерфейс, а не метод? Что касается Java7, который я использую, это недопустимо.
Аникет Тхакур
2
@AniketThakur. Это запрещено до Java 8. Эта функция добавлена ​​только в Java 8. Вы можете избежать предоставления реализации методов по умолчанию в вашем реализующем классе.
Рохит Джайн
1
@PawanMishra. См. Мой предыдущий комментарий. Нет, вам не нужно предоставлять реализацию методов интерфейса по умолчанию при реализации класса.
Рохит Джайн
1
@PawanMishra, вы можете переопределить его. Нет никаких ограничений, например, вам нужно использовать только реализацию по умолчанию.
Аникет Такур
4
Шаг вперед, который, наконец, позволит избежать множественного наследования!
Xtreme Biker
17

Я провел небольшое исследование и обнаружил следующее. Надеюсь это поможет.

Существующая проблема

Обычные методы интерфейса объявлены как абстрактные и должны быть определены в классе, реализующем интерфейс. Это «обременяет» разработчика класса ответственностью за реализацию каждого объявленного метода. Что еще более важно, это также означает, что расширение интерфейса невозможно после «публикации». В противном случае всем разработчикам пришлось бы адаптировать свою реализацию, нарушая обратную совместимость исходного кода и двоичную совместимость.

Решение принято в Java 8

Чтобы справиться с этими проблемами, одной из новых функций JDK 8 является возможность расширения существующих интерфейсов с помощью методов по умолчанию. Методы по умолчанию не только объявляются, но и определяются в интерфейсе.

Важные моменты на заметку

  1. Разработчики могут отказаться от реализации методов по умолчанию при реализации класса.
  2. Разработчики по-прежнему могут переопределять методы по умолчанию, например, обычные методы незавершенного класса могут быть переопределены в подклассах.
  3. Абстрактные классы могут даже (повторно) объявлять методы по умолчанию как абстрактные, вынуждая подклассы повторно реализовывать метод (иногда называемый «реабстракцией»).
Аникет Такур
источник