java函数接口覆盖

agxfikkp  于 2023-02-28  发布在  Java
关注(0)|答案(2)|浏览(98)
@FunctionalInterface
interface MyIF {

    void init();
    default void myTest() {
        System.out.println("myTest interface Method");
    }
}

class A implements MyIF {

    @Override
    public void init() {
        myTest();
    }

    @Override
    public void myTest() {
        System.out.println("myTest class Method");
    }
}

public class Main {
    public static void main(String[] args) {
        A a = new A();
        MyIF my = a::myTest;
        my.myTest(); 
  }
}
    • 产出**

myTest接口方法

    • 预期**

myTest类方法
我尝试了这段代码,并期待相同的结果:

A a = new A();
MyIF my = new A();
my.myTest();
    • 产出**

myTest类方法
为什么结果不同?

xsuvu9jc

xsuvu9jc1#

a::myTest表示使用myTest()作为函数接口MyIF的实现中所需的函数。它必须替换的函数是init()方法,而不是myTest方法。函数接口缺少一个实现,在这种情况下,它是init()方法。因此MyIF的这个新实现具有由a::myTest指定的init,以及由default void myTest()MyIF中指定的myTest。它不是A的示例:这就像拥有:

A a = new A();
MyIF my = new MyIF() {
    public void init() {
        a.myTest();
    }
};

在第二种情况下,您的my * 实际上是A的一个示例,并且类中的方法实现覆盖了接口中的默认实现,因此您从A获得了myTest方法。

pinkon5k

pinkon5k2#

这是一个很好的问题:)。
正如@khelwood所指出的,这句台词:

MyIF my = a::myTest;

创建到MyIF接口的init()方法的lambda绑定。
当编译器遇到这种情况时,它会创建一个新的MyIF引用,该引用只链接到A的示例,用于实现init()。由于编译器只能选择一个方法来提供@FunctionalInterface行为,它必须选择非默认的方法,否则编译器无法知道接口将哪个方法定义为它的函数/lambda签名。如果您尝试使用两个没有默认实现的标准接口方法,您将因此而得到一个编译器错误(即使签名不同)。
如果在代码中添加一行代码,可能会更清楚:

A a = new A();
        MyIF my = a::myTest;
        my.init();
        my.myTest();

现在,您可以在输出中看到,lambda调用的init()方法仍然调用A中的myTest()实现。
一般来说,避免函数接口中的默认实现以减少混淆可能是明智的:)。
Effective Java(第3版)第21项和第43项与此相关。

相关问题