Явное вызов метода по умолчанию в Java

Java 8 представляет методы по умолчанию, чтобы обеспечить возможность расширения интерфейсов без необходимости изменять существующие реализации.

Интересно, возможно ли явно вызвать реализацию метода по умолчанию, когда этот метод был переопределен или недоступен из-за противоречивых реализаций по умолчанию в различных интерфейсах.

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

Учитывая приведенный выше код, как бы вы вызвали A.foo() из метода класса B?

Ответ 1

Согласно этой статье вы получаете доступ к методу по умолчанию в интерфейсе A, используя

A.super.foo();

Это можно использовать следующим образом (при условии, что оба интерфейса A и C имеют методы по умолчанию 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
    }
}

A и C могут иметь методы .foo(), и может быть выбрана конкретная реализация по умолчанию, или вы можете использовать один (или оба) как часть вашего нового метода foo(). Вы также можете использовать тот же синтаксис для доступа к версиям по умолчанию в других методах в вашем классе реализации.

Формальное описание синтаксиса вызова метода можно найти в главе 15 JLS.

Ответ 2

Код ниже должен работать.

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

Вывод:

B.foo
A.foo

Ответ 3

Этот ответ предназначен в основном для пользователей, которые задают вопрос 45047550, который закрыт.

Интерфейсы Java 8 представляют некоторые аспекты множественного наследования. Методы по умолчанию имеют реализованную функцию body. Для вызова метода из суперкласса вы можете использовать ключевое слово super, но если вы хотите сделать это с помощью суперинтерфейса, необходимо указать его явно.

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

Выход:

Hello ParentClass!
Hello InterfaceFoo!
Hello InterfaceBar!

Ответ 4

Вам не нужно переопределять метод интерфейса по умолчанию. Просто назовите его следующим образом:

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

Выход:

A.foo