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

247

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?

GOTO 0
источник
Можете ли вы сказать мне, почему у вас есть реализация вашего метода foo () внутри вашего интерфейса A ??
Мацей Сиган,
20
@MaciejCygan Это разрешено в Java 8
Rohit Jain

Ответы:

330

Согласно этой статье вы получаете доступ к методу по умолчанию в интерфейсе, 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 .

Ричард Тингл
источник
14
Также обратите внимание, что если A extends SomeOtherInterfaceи SomeOtherInterfaceимеет default Type method(), то вы не можете просто позвонить SomeOtherInterface.super.method()из ChildClass. Вы можете вызывать только методы по умолчанию для интерфейсов, перечисленных в разделе ChildClass's implements, а не методы их родительских интерфейсов.
gvlasov
1
@ Сусейка хорошая точка, так же, как и нет super.super.someMethod();(потому что это было бы ужасно)
Ричард Тингл
@ gvlasov хороший момент, но как получить доступ к методу родительского интерфейса по умолчанию из дочернего интерфейса, возможно ли это ?? Обновление .......... Да Возможно, более конкретное объяснение здесь stackoverflow.com/a/24280376/3791156
Raaghu
@RichardTingle безупречный ответ!
Гаурав
17

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

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
Абхиджит Нагараджан
источник
Я думаю, что это лучший пример, который описывает вышеуказанный вопрос. Спасибо
Хемант Пила
8

Этот ответ написан в основном для пользователей, которые приходят с закрытого вопроса 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();
    }
}

Вывод:

Привет ParentClass!
Привет InterfaceFoo!
Привет InterfaceBar!

Давид Хорват
источник
3

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

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

Masudul
источник
9
OP говорит: «[возможно] ли можно явно вызвать реализацию метода по умолчанию, когда этот метод был переопределен»
dasblinkenlight