Java方法引用是否稳定?
如果使用新语法获取方法引用:Java方法引用是否稳定?,java,java-8,Java,Java 8,如果使用新语法获取方法引用: anObject::aMethod 我总是得到同样的东西吗?也就是说,我能相信对同一方法的两个引用是相等的吗 例如,如果我计划将它们用作可以添加和删除的Runnablecallbacks,那么这很好: someLibrary.addCallback(anObject::aMethod) // later someLibrary.removeCallback(sameObject::sameMethod) 这是否需要将引用保存在Runnable变量中以保持其稳定?
anObject::aMethod
我总是得到同样的东西吗?也就是说,我能相信对同一方法的两个引用是相等的吗
例如,如果我计划将它们用作可以添加和删除的Runnable
callbacks,那么这很好:
someLibrary.addCallback(anObject::aMethod)
// later
someLibrary.removeCallback(sameObject::sameMethod)
这是否需要将引用保存在
Runnable
变量中以保持其稳定?只需尝试一下即可得到答案:
Object object = ...;
Supplier<String> s1 = object::toString;
Supplier<String> s2 = object::toString;
System.out.println(s1.equals(s2));
对象对象=。。。;
供应商s1=对象::toString;
供应商s2=对象::toString;
系统输出println(s1等于(s2));
答案是。。。不幸的是没有
当然,如果您保持相同的引用(即相同的对象),它将起作用;但是,如上面的例子所示,如果您请求两个lambda,尽管它们看起来相同,但它们永远不会相等。
因此,reference=object::method
以及随后的remove(reference)
显然会起作用,但如果从集合中以文字形式编写,则从集合中删除(sameObject::sameMethod)将永远不会起作用
对于构造函数(例如ArrayList::new)和未绑定方法(例如Object::toString),答案也是否定的。似乎每次使用lambda表达式时都会构造一个新的lambda
正如@Hitobat所指出的,如果你想一想Lambda到底是什么以及它们来自哪里,这种不平等是有道理的。基本上,Supplier x=myObject::toString
是Supplier x=new Supplier(…)
的一个语法术语。如果没有适当的Object.equals重载,匿名类的两个实例显然是不同的。可能很多人都这么认为,我认为在某个地方有一种频繁使用的lambda缓存,以提高效率;好吧,一点也不。jl是关于从方法引用表达式中得到的内容的同一性或相等性
您可以运行快速测试:
Object obj = new Object();
IntSupplier foo = obj::hashCode;
IntSupplier bar = obj::hashCode;
System.out.println(foo == bar); // false
System.out.println(foo.equals(bar)); // false
但这当然取决于实现
您可以使lambda
可序列化
,并使用serlialized表示为回调映射设置键。看见虽然这可以工作,但规范并不要求它工作。如何实现removeCallback()
呢?lambda没有等于和hashCode
-请参见。顺便说一句,我不认为这是重复的。方法引用使用的语法不允许在闭包中捕获变量,除了this
。现在还不清楚它是否遵循与lambda表达式相同的规则(它们有充分的理由不成为稳定引用),我想回顾一下,这是有意义的。如果您认为方法引用只是较长匿名类“new Supplier(){…}”的语法糖,那么在不重载Object.equals的情况下,这些anon实例将不匹配.Exact。我将在我的答案中增加一个精确性。如中所述,该规范允许对象重用,并且在某些情况下(即不捕获lambda)已经发生了,但完全由JVM决定。由于JVM实现还具有转义分析,它可以透明地省略对象创建(即,supplier1==supplier2
被常量false
替换,但对象甚至可能不存在),这是合理的。性能很重要,而不是x==y
的结果…