如何在Java 8中比较函数式接口/方法引用

4

可以做类似这样的事情吗:

boolean isItMyMethod( Consumer<Object> aConsumer )
{
    return aConsumer.equals( this::myMethod );
}

这段代码无法编译通过。如果我将this::myMethod赋值给一个中间变量,它就可以编译通过了,但结果总是false。


我的方法是什么类型? - Utsav Dawn
使用案例是什么? - gontard
为什么你想这样做?顺便提一下,直接传递方法引用不起作用,因为 lambda 和方法引用的目标类型应该是一个函数式接口,而 Object 不是。 - Rohit Jain
2
无论如何,您不能依赖于.equals在lambda表达式或方法引用上返回一致的结果。 - Jeffrey Bosboom
2
换句话说,使用当前的实现,您可以说Consumer<Object> c1=this::myMethod, c2=this::myMethod;并且c1==c2c1.equals(c2)都将评估为false。因此,您可以修复代码以aConsumer.equals((Consumer<Object>) this::myMethod ),但它始终会产生false(使用当前的JRE实现)。请参见https://dev59.com/E14c5IYBdhLWcg3wM3-R。 - Holger
1个回答

5
一个方法引用或Lambda表达式的目标类型应该是一个函数式接口。由于equals()方法需要一个Object参数,而Object不是一个函数式接口,所以它无法编译。你可能会问为什么?因为在运行时,Lambda表达式或方法引用被实现为实现该函数式接口的类的实例。函数式接口只包含一个抽象方法,因此对于Lambda表达式x -> Sysout(x),左侧部分成为该方法的参数,右侧部分成为主体。
现在可以有许多提供这种方法签名的函数式接口。这意味着相同的Lambda表达式可以编译为不同的FI实现。当您将Lambda传递给像这样的Object引用时:
Object ob = x -> Sysout(x);

您希望JVM实例化哪个函数接口?这会导致某些不确定性,因此不被允许。但是通过将lambda预先分配给FI引用:
Consumer<Object> consumer = x -> Sysout(x);

您已经给Lambda分配了具体的含义,然后它可以被分配给任何超类型引用。

Object ob = consumer;

现在关于为什么equals()方法返回false,你可以猜测一下。由于Lambda是在运行时构造的类实例,它将提供FI中抽象方法的实现,那么你希望两个Consumer引用基于什么进行比较呢?由于没有重写equals()方法,它将调用Object类中的实现,该实现只比较引用。实现看起来像这样:
public boolean equals(Object ob) {
    return this == ob;
}

当两个变量分别指向不同的lambda表达式或方法引用时,aConsumer == bConsumer 将返回 false

即使aConsumer和bConsumer都引用相同的lambda表达式/方法引用,aConsumer == bConsumer可能会返回false - Holger
为什么没有重写equals()方法? - Basilevs

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