【问题标题】:How to compare functional interfaces / method references in java 8 [duplicate]如何比较java 8中的功能接口/方法引用[重复]
【发布时间】:2015-02-26 16:18:25
【问题描述】:

是否可以这样做:

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

这不会编译。如果我将 this::myMethod 分配给中间变量,它会这样做,但结果总是错误的。

【问题讨论】:

  • myMethod 的类型是什么?
  • 用例是什么?
  • 你为什么要这样做?顺便说一句,直接传递方法引用是行不通的,因为 lambda 和方法引用的目标类型应该是函数式接口,而 Object 不是这样。
  • 无论如何,你不能依赖 .equals 的 lambda 或方法引用来返回一致的结果。
  • 或者,换句话说,对于当前的实现,您可以说Consumer&lt;Object&gt; c1=this::myMethod, c2=this::myMethod;c1==c2c1.equals(c2) 都将评估为false。因此,您可以将代码修复为aConsumer.equals((Consumer&lt;Object&gt;) this::myMethod ),但它始终会产生false(使用当前的JRE 实现)。另见stackoverflow.com/q/28190304/2711488

标签: java lambda java-8


【解决方案1】:

方法引用或 lambda 的目标类型应该是函数式接口。由于equals() 方法采用Object,这不是一个功能接口,因此无法编译。现在你会说,为什么?好吧,lambda 表达式或方法引用在运行时被实现为实现该功能接口的类的实例。 FI 只包含一个抽象方法,因此对于 lambda x -&gt; Sysout(x),左侧部分成为该方法的参数,右侧部分成为主体。

现在可以有很多功能接口,提供这样的方法签名。这意味着可以编译相同的 lambda 表达式以实现不同的 FI。现在,当您将 lambda 传递给 Object 引用时,如下所示:

Object ob = x -> Sysout(x);

您希望 JVM 实例化哪个 FI?这会导致一定的歧义,因此是不允许的。但是通过将 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;
}

当然,aConsumer == bConsumer 将返回 false,如果两者都引用 2 个不同的 lambdas/方法引用。

【讨论】:

  • aConsumer == bConsumer 可能返回 false,即使两者都引用相同的 lambda 表达式/方法引用...
  • 为什么equals() 没有被覆盖?
猜你喜欢
  • 2023-04-04
  • 1970-01-01
  • 2013-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2018-01-11
相关资源
最近更新 更多