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

В java 8 у меня есть что-то вроде этого:

package test;
public class SimpleFuncInterfaceTest {
    public static void carryOutWork(AFunctionalInterface sfi){
        sfi.doWork();
    }
    public static void main(String[] args) {
        carryOutWork(() -> System.out.println("Do work in lambda exp impl..."));
        AImplementor implementsA = new AImplementor();
        //carryOutWork(() -> implementsA.doWork());
        BImplementor implementsB = new BImplementor();
        carryOutWork(() -> implementsB.doWork());
    }
}

@FunctionalInterface
interface AFunctionalInterface {
    public void doWork();
    default public void doSomeWork(){
        System.out.println("FOO");
    }
}

@FunctionalInterface
interface BFunctionalInterface extends AFunctionalInterface {
    @Override
    default public void doSomeWork(){
        System.out.println("BAR");//Unreachable in same object?
    }
}

class AImplementor implements AFunctionalInterface {
    @Override
    public void doWork() {
        doSomeWork();
    }
}

class BImplementor extends AImplementor implements BFunctionalInterface {
    public void doSomeWork(){
        super.doSomeWork();
        new BFunctionalInterface(){
            @Override
            public void doWork() {
            }}.doSomeWork();
            System.out.println("WUK WUK");
    }
    @Override
    public void doWork() {
        doSomeWork();
    }
}

Есть ли способ вызвать поведение функционального интерфейса по умолчанию из реализации B без необходимости создавать анонимный внутренний класс и вызывать его?

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

Например, если A разблокировал или предоставил доступ к ресурсу, скажем, к базе данных, а B разблокировал второй ресурс (другую базу данных), я не вижу способа заставить код разблокировать A, а затем B обеспечить выполнение этого контракта с помощью функциональных интерфейсов, требуя, чтобы А и Б называться. На один уровень в глубину вы можете это сделать, но на N уровней похоже, что это невозможно.

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

Этот вопрос не совсем не похож на «Явный вызов метода по умолчанию в Java», поскольку этот вопрос касается интерфейсов на уровне N, а не просто вызова метода родительских интерфейсов по умолчанию.


person ggb667    schedule 17.06.2014    source источник
comment
Итак, вы хотите позвонить BFunctionalInterface.doSomeWork из BImplementor?   -  person Boris the Spider    schedule 18.06.2014
comment
Это не тот же вопрос, что и явный вызов метода по умолчанию в Java, здесь задается N уровней глубины, тогда как это решение допускает только один уровень косвенности.   -  person ggb667    schedule 03.01.2017


Ответы (1)


Вы можете вызвать унаследованный метод interface default с помощью InterfaceName.super. Правила такие же, как и для других вызовов метода super: вы можете вызвать унаследованный метод, который вы переопределили, но вы не можете напрямую вызвать метод, который унаследованный метод мог переопределить. Например.

interface A
{
    void foo();
    default void toOverride() {
        System.out.println("A");
    }
}
interface B extends A
{
    default void toOverride() {
        A.super.toOverride();
        System.out.println("B");
    }
}
interface C extends B
{
    default void toOverride() {
        A.super.toOverride();// does not work
        B.super.toOverride();
        System.out.println("B");
    }
}
class D implements B
{
    public void toOverride() {

    }    
    public void foo() {
        D.this.toOverride();
        B.super.toOverride();
        A.super.toOverride(); // does not work!
    }
}

Но если каждый переопределяющий метод вызывает свой суперметод, вы получаете цепочку вызовов. Однако имейте в виду, что мы говорим об интерфейсах. Реализация всегда может переопределить метод по умолчанию, вообще не вызывая super.

person Holger    schedule 18.06.2014