Llamando explícitamente un método predeterminado en Java

247

Java 8 presenta métodos predeterminados para proporcionar la capacidad de extender interfaces sin la necesidad de modificar las implementaciones existentes.

Me pregunto si es posible invocar explícitamente la implementación predeterminada de un método cuando ese método se ha anulado o no está disponible debido a implementaciones predeterminadas conflictivas en diferentes interfaces.

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 el código anterior, ¿cómo llamarías A.foo()desde un método de clase B?

GOTO 0
fuente
¿Me puede decir por qué tiene la implementación de su método foo () dentro de su interfaz A ??.
Maciej Cygan
20
@MaciejCygan Está permitido en Java 8
Rohit Jain

Respuestas:

330

Según este artículo , accede al método predeterminado en la interfaz Ausando

A.super.foo();

Esto podría usarse de la siguiente manera (suponiendo que las interfaces Ay Cambas tienen métodos predeterminados 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
    }
}

Ay Cpueden tener .foo()métodos y se puede elegir la implementación predeterminada específica o puede usar uno (o ambos) como parte de su nuevo foo()método. También puede usar la misma sintaxis para acceder a las versiones predeterminadas en otros métodos en su clase de implementación.

La descripción formal de la sintaxis de invocación del método se puede encontrar en el capítulo 15 de la JLS .

Richard Tingle
fuente
14
También tenga en cuenta que si A extends SomeOtherInterface, y SomeOtherInterfacetiene default Type method(), entonces no puede simplemente llamar SomeOtherInterface.super.method()desde ChildClass. Solo puede llamar a los métodos predeterminados de las interfaces enumeradas en la cláusula ChildClass's implements, no a los métodos de sus interfaces principales.
gvlasov
1
@Suseika buen punto, lo mismo que no hay super.super.someMethod();(porque eso sería horrible)
Richard Tingle
@gvlasov buen punto, pero ¿cómo acceder al método predeterminado de una interfaz principal desde una interfaz secundaria, es posible? Actualización .......... Sí Posible, la explicación más concreta aquí stackoverflow.com/a/24280376/3791156
Raaghu
@RichardTingle respuesta perfecta!
gaurav
17

El siguiente código debería funcionar.

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

Salida:

B.foo
A.foo
Abhijith Nagarajan
fuente
Creo que este es el mejor ejemplo que describe la pregunta anterior. Gracias
Hemanth Peela
8

Esta respuesta está escrita principalmente para usuarios que provienen de la pregunta 45047550 que está cerrada.

Las interfaces Java 8 introducen algunos aspectos de la herencia múltiple. Los métodos predeterminados tienen un cuerpo de función implementado. Para llamar a un método desde la superclase, puede usar la palabra clave super, pero si desea hacer esto con una súper interfaz, debe nombrarlo explícitamente.

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

Salida:

Hola ParentClass!
Hola InterfaceFoo!
Hola InterfaceBar!

Dávid Horváth
fuente
3

No necesita anular el método predeterminado de una interfaz. Solo llámalo así:

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

Salida:

A.foo

Masudul
fuente
99
OP dice: "[es posible] invocar explícitamente la implementación predeterminada de un método cuando ese método ha sido anulado"
dasblinkenlight