在Java中显式调用默认方法

345

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?
    }
}
考虑上面的代码,如何从类B的一个方法中调用A.foo()?

你能告诉我为什么在接口A中有foo()方法的实现吗? - Maciej Cygan
24
可以在Java 8中实现。 - Rohit Jain
7个回答

472
根据这篇文章,您可以使用以下方法访问接口A中的默认方法。
A.super.foo();

这可以如下使用(假设接口 AC 都有默认方法 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
    }
}

AC都可以有.foo()方法,可以选择特定的默认实现,或者将其作为新foo()方法的一部分使用(或两者都使用)。您还可以使用相同的语法在实现类中的其他方法中访问默认版本。

有关方法调用语法的正式描述,请参见JLS第15章


29
请注意,如果A继承自SomeOtherInterface,并且SomeOtherInterface拥有一个默认的类型为Type的方法method(),那么你无法直接从ChildClass中调用SomeOtherInterface.super.method()。你只能调用ChildClass实现接口中枚举的接口的默认方法,而不能调用其父接口的方法。 - gvlasov
1
@Suseika 说得好,就像没有 super.super.someMethod();(因为那会很糟糕)。 - Richard Tingle
2
@gvlasov 说得不错,但是如何从子接口访问父接口的默认方法,这可行吗?? 更新........ 是可行的,在此处有更具体的解释 https://dev59.com/62Af5IYBdhLWcg3wylId#24280376 - Raaghu
Interface.super.method() 的背后逻辑是什么?为什么不直接使用 Interface.method() - tejasvi88
1
@tejasvi88 Interface.method() 意味着 Interface 中的静态方法。它是一种“超级”的方式,因此超级部分可以说是最重要的。 - Richard Tingle
显示剩余2条评论

23

这篇答案主要是为了那些来自问题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!


19

下面的代码应该可以正常工作。

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

我认为这是最好的例子,可以描述上述问题。谢谢。 - Hemanth Peela

6

您不需要覆盖接口的默认方法。只需按照以下方式调用即可:

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

Output:

A.foo


11
OP 说:当一个方法被重写后,是否可以显式地调用默认实现? - Sergey Kalinichenko

0

这取决于您是否要覆盖接口的默认方法。因为默认方法类似于类的实例方法,可以直接调用实现类对象。(简而言之,接口的默认方法由实现类继承)


0

考虑以下示例:

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

0

调用Java8函数式接口的默认方法

@Functional Interface
interface Process {
   String preInit();
   default String postInit() {
       return "PostInit";
   }
}

public class ProcessImpl {
  Process process = () -> ("PreInit");
  String preInit = process.preInit();
  String postInit = process.postInit(); // Calling default method "postInit()" from functional interface
  System.out.println(preInit);
  System.out.println(postInit);
}

Output:
PreInit
PostInit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接