Що таке “типова” реалізація методу, визначеного в інтерфейсі?


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ключове слово і як воно працює?


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 представляє нову функцію «Метод за замовчуванням» або (методи Defender), що дозволяє розробнику додавати нові методи до інтерфейсів, не порушуючи існуючу реалізацію цього інтерфейсу. Він забезпечує гнучкість, дозволяючи інтерфейсу визначати реалізацію, яка використовуватиметься за замовчуванням у ситуації, коли конкретний клас не може забезпечити реалізацію для цього методу.

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

18
Дякую, справді непогана експозиція. Ви відповіли на всі мої запитання до того, як я мав можливість їх задати.
Jeff Hutchins

чому б не використовувати замість цього абстрактне?
Astolfo Hoscher

1
@AstolfoHoscher Ви можете розширити лише один клас, але ви можете реалізувати кілька інтерфейсів.
Чарльз Вуд,

49

Ці методи називаються методами за замовчуванням. Метод за замовчуванням або метод Defender - одна з нещодавно доданих функцій 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, який я використовую, це заборонено.
Aniket Thakur

2
@AniketThakur. Це заборонено до Java 8. Ця функція додана лише в Java 8. Ви можете уникнути реалізації методів за замовчуванням у своєму класі реалізації.
Rohit Jain

1
@PawanMishra. Дивіться мій попередній коментар. Ні, вам не потрібно надавати реалізацію методів інтерфейсу за замовчуванням у реалізації класу.
Rohit Jain

1
@PawanMishra, ви можете це замінити. Не існує жодних обмежень, тому що вам потрібно використовувати лише реалізацію за замовчуванням.
Aniket Thakur

4
Крок вперед, який нарешті не дозволить спантеличити багаторазове успадкування!
Xtreme Biker

17

Я трохи дослідив і виявив наступне. Сподіваюся, це допомагає.

Існуюча проблема

Звичайні методи інтерфейсу оголошуються абстрактними і повинні бути визначені в класі, який реалізує інтерфейс. Це 'навантажує' реалізатора класу відповідальністю реалізувати кожен заявлений метод. Що ще важливіше, це також означає, що розширення інтерфейсу неможливо після "публікації". В іншому випадку всі виконавці повинні були б адаптувати їх реалізацію, порушуючи зворотну сумісність джерел та бінарних файлів.

Рішення, прийняте в Java 8

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

Важливі зауваження

  1. Реалізатори можуть не застосовувати методи за замовчуванням у реалізації класу.
  2. Реалізатори все ще можуть замінити методи за замовчуванням, як звичайні нефінальні методи класу можна замінити в підкласах.
  3. Абстрактні класи можуть навіть (повторно) оголосити методи за замовчуванням як абстрактні, змушуючи підкласи перевтілювати метод (іноді його називають "повторною абстракцією").
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.