Chiamare esplicitamente un metodo predefinito in Java


247

Java 8 introduce metodi predefiniti per fornire la possibilità di estendere le interfacce senza la necessità di modificare le implementazioni esistenti.

Mi chiedo se sia possibile invocare esplicitamente l'implementazione predefinita di un metodo quando tale metodo è stato sovrascritto o non è disponibile a causa di implementazioni predefinite contrastanti in diverse interfacce.

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

class B implements A {
    @Override
    public void foo() {
        System.out.println("B.foo");
    }
    public void afoo() {
        // how to invoke A.foo() here?
    }
}

Considerando il codice sopra, come chiameresti A.foo()da un metodo di classe B?


Puoi dirmi perché hai implementato il tuo metodo foo () all'interno della tua interfaccia A ??.
Maciej Cygan,

20
@MaciejCygan È consentito in Java 8
Rohit Jain il

Risposte:


330

Come da questo articolo si accede al metodo predefinito nell'interfaccia Autilizzando

A.super.foo();

Questo potrebbe essere usato come segue (supponendo che le interfacce Aed Centrambe abbiano metodi predefiniti foo())

public class ChildClass implements A, C {
    @Override    
    public void foo() {
       //you could completely override the default implementations
       doSomethingElse();
       //or manage conflicts between the same method foo() in both A and C
       A.super.foo();
    }
    public void bah() {
       A.super.foo(); //original foo() from A accessed
       C.super.foo(); //original foo() from C accessed
    }
}

Ae Cpossono avere entrambi .foo()metodi e può essere scelta l'implementazione predefinita specifica oppure puoi usarne uno (o entrambi) come parte del tuo nuovofoo() metodo. È inoltre possibile utilizzare la stessa sintassi per accedere alle versioni predefinite in altri metodi nella classe di implementazione.

La descrizione formale della sintassi di invocazione del metodo è disponibile nel capitolo 15 della JLS .


14
Nota anche che A extends SomeOtherInterface, se lo SomeOtherInterfaceè default Type method(), non puoi semplicemente chiamare SomeOtherInterface.super.method()da ChildClass. È possibile chiamare solo i metodi predefiniti delle interfacce enumerate nella clausola ChildClass"s implements", non i metodi delle loro interfacce parent.
gvlasov,

1
@Suseika buon punto, lo stesso che non c'è super.super.someMethod();(perché sarebbe orribile)
Richard Tingle,

@gvlasov buon punto, ma come accedere al metodo predefinito di un'interfaccia genitore da un'interfaccia figlio, è possibile ?? Aggiornamento .......... Sì Possibile, la spiegazione più concreta qui stackoverflow.com/a/24280376/3791156
Raaghu

@RichardTingle risposta impeccabile!
gaurav,

17

Il codice seguente dovrebbe funzionare.

public class B implements A {
    @Override
    public void foo() {
        System.out.println("B.foo");
    }

    void aFoo() {
        A.super.foo();
    }

    public static void main(String[] args) {
        B b = new B();
        b.foo();
        b.aFoo();
    }
}

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

Produzione:

B.foo
A.foo

Penso che questo sia il miglior esempio che descriva la domanda sopra. Grazie
Hemanth Peela,

8

Questa risposta è scritta principalmente per gli utenti che provengono dalla domanda 45047550 che è chiusa.

Le interfacce Java 8 introducono alcuni aspetti dell'ereditarietà multipla. I metodi predefiniti hanno un corpo di funzione implementato. Per chiamare un metodo dalla super classe puoi usare la parola chiave super, ma se vuoi farlo con una super interfaccia è necessario nominarlo esplicitamente.

class ParentClass {
    public void hello() {
        System.out.println("Hello ParentClass!");
    }
}

interface InterfaceFoo {
    default public void hello() {
        System.out.println("Hello InterfaceFoo!");
    }
}

interface InterfaceBar {
    default public void hello() {
        System.out.println("Hello InterfaceBar!");
    }
}

public class Example extends ParentClass implements InterfaceFoo, InterfaceBar {
    public void hello() {
        super.hello(); // (note: ParentClass.super is wrong!)
        InterfaceFoo.super.hello();
        InterfaceBar.super.hello();
    }

    public static void main(String[] args) {
        new Example().hello();
    }
}

Produzione:

Ciao ParentClass!
Ciao InterfaceFoo!
Ciao InterfaceBar!


3

Non è necessario sovrascrivere il metodo predefinito di un'interfaccia. Basta chiamarlo come segue:

public class B implements A {

    @Override
    public void foo() {
        System.out.println("B.foo");
    }

    public void afoo() {
        A.super.foo();
    }

    public static void main(String[] args) {
       B b=new B();
       b.afoo();
    }
}

Produzione:

A.foo


9
OP dice: "[è possibile] invocare esplicitamente l'implementazione predefinita di un metodo quando quel metodo è stato sovrascritto"
dasblinkenlight
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.