Явный вызов метода по умолчанию в 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?


person GOTO 0    schedule 14.11.2013    source источник
comment
Можете ли вы сказать мне, почему у вас есть реализация вашего метода foo () внутри вашего интерфейса A ??.   -  person Maciej Cygan    schedule 14.11.2013
comment
@MaciejCygan Это разрешено в Java 8   -  person Rohit Jain    schedule 14.11.2013


Ответы (6)


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

person Richard Tingle    schedule 14.11.2013
comment
Также обратите внимание, что если A extends SomeOtherInterface и SomeOtherInterface имеет default Type method(), вы не можете просто вызвать SomeOtherInterface.super.method() из ChildClass. Вы можете вызывать только методы по умолчанию для интерфейсов, перечисленных в предложении ChildClass implements, но не методы их родительских интерфейсов. - person gvlasov; 25.05.2015
comment
@Suseika хороший замечание, то же самое, что нет super.super.someMethod(); (потому что это было бы ужасно) - person Richard Tingle; 25.05.2015
comment
@gvlasov хороший вопрос, но как получить доступ к методу по умолчанию родительского интерфейса из дочернего интерфейса, возможно ли это ?? Обновить .......... Да Возможно, более конкретное объяснение здесь stackoverflow.com/a/24280376/3791156 - person Raaghu; 02.01.2018
comment
@RichardTingle безупречный ответ! - person Gaurav; 08.08.2019
comment
В чем причина Interface.super.method()? Почему не просто Interface.method()? - person tejasvi88; 10.06.2021
comment
@ tejasvi88 Interface.method() будет подразумевать статический метод в Interface. Это своего рода супер, поэтому супер часть, пожалуй, самая важная. - person Richard Tingle; 10.06.2021

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

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
person Abhijith Nagarajan    schedule 14.11.2013
comment
Я думаю, что это лучший пример, который описывает поставленный выше вопрос. Спасибо - person Hemanth Peela; 10.02.2019

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

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

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

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

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

public class Example extends ParentClass implements InterfaceFoo, InterfaceBar {
    public void hello() {
        super.hello(); // (note: ParentClass.super could not be used)
        InterfaceFoo.super.hello();
        InterfaceBar.super.hello();
    }
    
    public static void main(String[] args) {
        new Example().hello();
    }
}

Вывод:

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

person Dávid Horváth    schedule 20.05.2018

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

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

person Masudul    schedule 14.11.2013
comment
OP говорит: [возможно ли] явно вызвать реализацию метода по умолчанию, когда этот метод был переопределен - person Sergey Kalinichenko; 14.11.2013

От вашего выбора зависит, хотите ли вы переопределить метод интерфейса по умолчанию или нет. Потому что по умолчанию они похожи на метод экземпляра класса, который может быть напрямую вызван на реализующем объекте класса. (Короче говоря, метод интерфейса по умолчанию наследуется путем реализации класса)

person Utpal Kumar    schedule 02.01.2021

Рассмотрим следующий пример:

interface I{
    default void print(){
    System.out.println("Interface");
    }
}

abstract class Abs{
    public void print(){
        System.out.println("Abstract");
    }

}

public class Test extends Abs implements I{

    public static void main(String[] args) throws ExecutionException, InterruptedException 
    {

        Test t = new Test();
        t.print();// calls Abstract's print method and How to call interface's defaut method?
     }
}
person Nomeswaran    schedule 24.04.2021