Java方法引用是否稳定?

sle*_*ica 23 java java-8

如果我使用新语法获取方法引用:

anObject::aMethod
Run Code Online (Sandbox Code Playgroud)

我总是得到同一个对象吗?也就是说,我可以相信对同一方法的两个引用是相同的吗?

例如,我很乐意知道是否计划将它们用作Runnable我可以添加和删除的回调:

someLibrary.addCallback(anObject::aMethod)
// later
someLibrary.removeCallback(sameObject::sameMethod)
Run Code Online (Sandbox Code Playgroud)

这是否需要在Runnable变量中保存引用以保持其稳定?

Mis*_*sha 17

JLS 对于从方法引用表达式中获取的内容的身份或相等性没有任何承诺.

你可以运行一个快速测试:

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      
Run Code Online (Sandbox Code Playgroud)

但这当然取决于实现.

可以创建lambda Serializable并使用serlialized表示键回调回调映射.请参见如何序列化lambda?.虽然这可行,但并不是完全需要按规格工作.


Que*_*inC 7

试试这个来得到答案:

Object object = ...;
Supplier<String> s1 = object::toString;
Supplier<String> s2 = object::toString;
System.out.println(s1.equals(s2));
Run Code Online (Sandbox Code Playgroud)

答案是......不幸的是没有.

当然,如果你保持相同的参考(即同一个对象),它将起作用; 但是,如果像上面的例子那样,你要求两个lambdas,虽然它们似乎是相同的,但它们永远不会相等.因此reference = object::method,后来remove(reference)显然会起作用,但remove(sameObject::sameMethod)如果它是文字书面的话,从集合中将永远不会起作用.

对于构造函数(例如ArrayList :: new)和未绑定方法(例如Object :: toString),答案也是否定的.似乎每次使用lambda表达式时都会构造一个新的lambda.

正如@Hitobat指出的那样,如果你想一下lambda究竟是什么以及它们来自哪里,这种不平等是有道理的.Supplier<String> x = myObject::toString基本上,是一种语法糖Supplier<String> x = new Supplier<String>( ... ).如果没有正确的Object.equals重载,匿名类的两个实例显然是不同的.可能和很多人一样,我觉得在某个地方有一种经常使用的lambdas缓存可以提高效率; 好吧,一点也不.

  • 我想这回想起来是有道理的.如果您认为方法引用只是较长的匿名类"new Supplier(){...}"的语法糖,那么在不重载`Object.equals`的情况下,这些anon实例将不匹配. (2认同)