Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java方法引用是否稳定?_Java_Java 8 - Fatal编程技术网

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
的结果…