Я знаю, что есть много вопросов по этому вопросу, даже совсем недавний , но я все еще не могу обдумать одну вещь.Рассмотрим следующий функциональный интерфейс :
@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"
Мне кажется, что в первом примере лямбда захватила состояние объекта 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());
Теперь я вижу, чтоони оба выводят "Alice"
, даже если p1 равно нулю, и поэтому ссылка на метод захватывает сам экземпляр, а не его состояние, как я ошибочно предположил.