我知道这个问题有很多相关的问题,甚至有一个最近的,但是我仍然无法理解一个问题。考虑下面的函数接口:
@FunctionalInterface
interface PersonInterface {
String getName();
}
并且这个实现:
class Person implements PersonInterface {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
如果我查看这些线程1和2,我期望以下代码将输出"Bob"
而不会抛出NullPointerException
,因为据我所知,当我创建我的供应商时,它会捕获Person
实例。Person p = new Person("Bob");
Supplier<String> f = p::getName;
p = null;
System.out.println(f.get());
它正确地输出了"Bob"
现在我不理解的是,为什么以下代码也没有输出"Bob"
?
Person p = new Person("Bob");
Supplier<String> f = p::getName;
p.setName("Alice");
System.out.println(f.get());
实际上,它输出"Alice"
在我看来,在第一个示例中,lambda在创建Person对象时捕获了其状态,并在调用时不尝试重新评估它;而在第二种情况下,它似乎没有捕获它,但在调用时重新评估了它。
编辑 在重新阅读其他线程并得到Eran的答案后,我写了那段关于两个指向同一实例的Person的代码:
Person p1 = new Person("Bob");
Person p2 = p1;
Supplier<String> f1 = p1::getName;
Supplier<String> f2 = p2::getName;
p1 = null;
p2.setName("Alice");
System.out.println(f1.get());
System.out.println(f2.get());
现在我可以看到,尽管p1为null,但它们都输出"Alice"
,因此方法引用捕获了实例本身,而不是我错误地假设的其状态。
"Alice"
,尽管p1为空,所以方法引用捕获了实例本身,而不是我错误地认为的其状态。