您可以将方法引用存储到变量中:
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
FunctionSet functionSet = new FunctionSet();
Element fn = functionSet::doubleUp;
set.add(fn);
set.add(functionSet::square);
System.out.println(set.add(fn));
}
这样它返回false。
当您在不同的代码位置创建相同的 labmda 或方法引用时,它与您在两个位置创建一个新的匿名类大致相同:
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
FunctionSet functionSet = new FunctionSet();
set.add(new Element() {
@Override
public void doSomething(int a) {
functionSet.doubleUp(a);
}
});
set.add(new Element() {
@Override
public void doSomething(int a) {
functionSet.square(a);
}
});
System.out.println(set.add(new Element() {
@Override
public void doSomething(int a) {
functionSet.doubleUp(a);
}
}));
}
所以每次它都是一个不同的对象,尽管它可能看起来一样。对于每个遇到的方法引用,都会在运行时创建单独的匿名类:
Element e1 = functionSet::doubleUp;
Element e2 = functionSet::doubleUp;
System.out.println(e1.getClass());
System.out.println(e2.getClass());
输出将是这样的:
class FunctionSet$$Lambda$1/918221580
class FunctionSet$$Lambda$2/1554547125
所以实际上它是两个不同类的两个不同对象。如果不比较它们的字节码,就很难断定它们做了同样的事情。另请注意,它们都捕获functionSet
变量,因此还应确保它在两个方法引用之间没有更改。
我能想到的唯一解决方法是将所有方法引用声明为代码中的常量,然后再引用它们,而不是直接使用方法引用:
public static final Element FN_DOUBLE_UP = new FunctionSet()::doubleUp;
public static final Element FN_SQUARE = new FunctionSet()::square;
public static void main(String[] args) {
HashSet<Element> set = new HashSet<>();
set.add(FN_DOUBLE_UP);
set.add(FN_SQUARE);
System.out.println(set.add(FN_DOUBLE_UP));
}