Chamar explicitamente um método padrão em Java

247

O Java 8 apresenta métodos padrão para fornecer a capacidade de estender interfaces sem a necessidade de modificar implementações existentes.

Gostaria de saber se é possível invocar explicitamente a implementação padrão de um método quando esse método foi substituído ou não está disponível devido a implementações padrão conflitantes em 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 o código acima, como você chamaria A.foo()de um método da classe B?

GOTO 0
fonte
Você pode me dizer por que você implementou o método foo () dentro da interface A ??.
Maciej Cygan
20
@MaciejCygan É permitido em Java 8
Rohit Jain

Respostas:

330

Conforme este artigo, você acessa o método padrão na interface Ausando

A.super.foo();

Isso pode ser usado da seguinte maneira (assumindo interfaces Ae Cambos têm métodos padrão 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 Cambos podem ter .foo()métodos e a implementação padrão específica pode ser escolhida ou você pode usar um (ou ambos) como parte do seu novo foo()método. Você também pode usar a mesma sintaxe para acessar as versões padrão em outros métodos em sua classe de implementação.

A descrição formal da sintaxe de chamada do método pode ser encontrada no capítulo 15 do JLS .

Richard Tingle
fonte
14
Observe também que se A extends SomeOtherInterface, e SomeOtherInterfacepossui default Type method(), você não pode simplesmente ligar SomeOtherInterface.super.method()do ChildClass. Você pode chamar apenas métodos padrão de interfaces enumerados na cláusula ChildClass's implements, não os métodos de suas interfaces pai.
Gvlasov # 25/15
1
@Suseika bom ponto, o mesmo que não existe super.super.someMethod();(porque isso seria horrível)
Richard Tingle
@gvlasov bom ponto, mas como acessar o método padrão de uma interface pai a partir de uma interface filho, é possível? Atualização .......... Sim Possível, a explicação mais concreta aqui stackoverflow.com/a/24280376/3791156
Raaghu
@RichardTingle resposta perfeita!
gaurav
17

O código abaixo deve 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");
    }
}

Resultado:

B.foo
A.foo
Abhijith Nagarajan
fonte
Eu acho que este é o melhor exemplo que descreve a pergunta acima. Obrigado
Hemanth Peela
8

Esta resposta foi escrita principalmente para usuários provenientes da pergunta 45047550, que está encerrada.

As interfaces Java 8 apresentam alguns aspectos da herança múltipla. Métodos padrão tem um corpo de função implementado. Para chamar um método da superclasse, você pode usar a palavra-chave super, mas se quiser fazer isso com uma super interface, é necessário nomeá-lo explicitamente.

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

Resultado:

Olá ParentClass!
Olá InterfaceFoo!
Olá InterfaceBar!

Dávid Horváth
fonte
3

Você não precisa substituir o método padrão de uma interface. Basta chamá-lo da seguinte maneira:

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

Resultado:

A.foo

Masudul
fonte
9
O OP diz: "[é] possível invocar explicitamente a implementação padrão de um método quando esse método foi substituído"
dasblinkenlight