Qual è l'implementazione "predefinita" del metodo definito in un'interfaccia?


91

Nell'interfaccia di raccolta ho trovato un metodo denominato removeIf()che contiene la sua implementazione.

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

Voglio sapere se esiste un modo per definire il corpo del metodo in un'interfaccia?
Qual è la defaultparola chiave e come funziona?



Risposte:


162

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

Java 8 introduce la nuova funzionalità "Metodo predefinito" o (metodi Defender), che consente allo sviluppatore di aggiungere nuovi metodi alle interfacce senza interrompere l'implementazione esistente di queste interfacce. Fornisce flessibilità per consentire l'implementazione della definizione dell'interfaccia che verrà utilizzata come impostazione predefinita nella situazione in cui una classe concreta non riesce a fornire un'implementazione per quel metodo.

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

public class ClassAB implements A {
}

C'è una domanda comune che le persone chiedono sui metodi predefiniti quando sentono parlare della nuova funzionalità per la prima volta:

E se la classe implementa due interfacce ed entrambe definiscono un metodo predefinito con la stessa firma?

Esempio per illustrare questa situazione:

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 {

}  

Questo codice non viene compilato con il seguente risultato:

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

Per risolvere questo problema, in Clazz, dobbiamo risolverlo manualmente sovrascrivendo il metodo in conflitto:

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

Ma cosa succederebbe se volessimo chiamare l'implementazione predefinita del metodo foo () dall'interfaccia A invece di implementare la nostra.

È possibile fare riferimento a A # foo () come segue:

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

18
Grazie, ottima esposizione. Hai risposto a tutte le mie domande prima che potessi farle.
Jeff Hutchins

perché non usare invece abstract?
Astolfo Hoscher

1
@AstolfoHoscher Puoi estendere solo una classe, ma puoi implementare più interfacce.
Charles Wood

49

Questi metodi sono chiamati metodi predefiniti. Il metodo predefinito o il metodo Defender è una delle nuove funzionalità aggiunte in Java 8.

Verranno utilizzati per consentire a un metodo di interfaccia di fornire un'implementazione utilizzata come predefinita nel caso in cui una classe concreta non fornisca un'implementazione per quel metodo.

Quindi, se hai un'interfaccia, con un metodo predefinito:

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

La seguente classe è perfettamente valida:

public class HelloImpl implements Hello {

}

Se crei un'istanza di HelloImpl:

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

Link utili:


Quindi va bene se una classe implementa un'interfaccia e non implementa il suo metodo? Per quanto riguarda Java7, il mio utilizzo non è consentito.
Aniket Thakur

2
@AniketThakur. Questo non è consentito prima di Java 8. Questa funzione viene aggiunta solo in Java 8. È possibile evitare di fornire l'implementazione dei metodi predefiniti nella classe di implementazione.
Rohit Jain

1
@PawanMishra. Vedi il mio commento precedente. No, non è necessario fornire l'implementazione dei metodi di interfaccia predefiniti nell'implementazione della classe.
Rohit Jain

1
@PawanMishra puoi comunque sovrascriverlo. Non ci sono restrizioni in quanto è necessario utilizzare solo l'implementazione predefinita.
Aniket Thakur

4
Un passo in avanti che eviterà finalmente di essere sconcertato dall'eredità multipla!
Xtreme Biker

17

Ho fatto un po 'di ricerca e ho trovato quanto segue. Spero che questo ti aiuti.

Problema esistente

I normali metodi di interfaccia sono dichiarati astratti e devono essere definiti nella classe che implementa l'interfaccia. Questo "grava" sull'implementatore della classe con la responsabilità di implementare ogni metodo dichiarato. Ancora più importante, questo significa anche che non è possibile estendere un'interfaccia dopo la "pubblicazione". Altrimenti, tutti gli implementatori dovrebbero adattare la loro implementazione, interrompendo la compatibilità con i sorgenti e i binari all'indietro.

Soluzione adottata in Java 8

Per far fronte a questi problemi, una delle nuove funzionalità di JDK 8 è la possibilità di estendere le interfacce esistenti con metodi predefiniti. I metodi predefiniti non sono solo dichiarati, ma anche definiti nell'interfaccia.

Punti importanti da notare

  1. Gli implementatori possono scegliere di non implementare metodi predefiniti nella classe di implementazione.
  2. Gli implementatori possono ancora sovrascrivere i metodi predefiniti, come i normali metodi di classe non finale possono essere sovrascritti nelle sottoclassi.
  3. Le classi astratte possono persino (ri) dichiarare i metodi predefiniti come astratti, costringendo le sottoclassi a reimplementare il metodo (a volte chiamato "ri-astrazione").
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.