Просто пытаюсь объяснить на примере полностью. Что произойдет с вашим кодом (, измененным для более читабельного вывода ) следующим образом:
Первый экземпляр
Rat rat1 = new Rat(game);
выполняется как:
this ----> pack.Sample$Rat@4cf777e8
sender ----> pack.Sample$Rat@4cf777e8
pack.Sample$Rat@4cf777e8 this ----> sender pack.Sample$Rat@4cf777e8
Простой, верно? Я полагаю, что это было само собой разумеющимся, поскольку был создан единственный экземпляр ( 4cf777e8 ), просто список с одним потребителем, и все работает, как ожидалось.
Второй экземпляр
Затем при второй инициализации
Rat rat2 = new Rat(game);
вы теперь создали еще один экземпляр Rat
( 5702b3b1 ), который теперь становится sender
в вашем Event.invoke
вызове как:
// part-1
this ----> pack.Sample$Rat@5702b3b1
// part-2
sender ----> pack.Sample$Rat@5702b3b1
pack.Sample$Rat@4cf777e8 this ----> sender pack.Sample$Rat@5702b3b1
sender ----> pack.Sample$Rat@5702b3b1
pack.Sample$Rat@5702b3b1 this ----> sender pack.Sample$Rat@5702b3b1
вывод, который вы видите, разделен на две части, первая часть печатает текущий экземпляр этого и отправителя, который является последним созданным экземпляром.
Вторая часть имеет решающее значение, поскольку теперь она имеет List<BiConsumer<Object, T>>
, в этом списке также есть предыдущий экземпляр Rat
( 4cf777e8 ), и это причина, по которой вы выполняете consumer.accept(sender, arg);
, первый экземпляр появляется на рисунке: this
указывает на его экземпляр и sender
указывает на текущий sender
, который вы передали в аргумент.
Третий экземпляр
Далее при последней инициализации
Rat rat3 = new Rat(game);
Теперь вы можете видеть, как вырос список consumers
и его влияние на результат. Имейте в виду, что список теперь имеет BiConsumer
с, каждый для созданного экземпляра Rat
, т.е. Крыса (4cf777e8) , Крыса (5702b3b1) и Крыса @ 69ea3742 , как вы заметили бы на выходе.
// part-1
this ----> pack.Sample$Rat@69ea3742
// part-2
sender ----> pack.Sample$Rat@69ea3742
pack.Sample$Rat@4cf777e8 this ----> sender pack.Sample$Rat@69ea3742 // (first element in list)
sender ----> pack.Sample$Rat@69ea3742
pack.Sample$Rat@5702b3b1 this ----> sender pack.Sample$Rat@69ea3742 // (second element in list)
sender ----> pack.Sample$Rat@69ea3742
pack.Sample$Rat@69ea3742 this ----> sender pack.Sample$Rat@69ea3742 // (third element in list)
упрощенный
Упрощенная версия вашего кода, чтобы проверить, что я придумал:
public static class Event {
private List<Consumer<Object>> consumers = new ArrayList<>();
void subscribe(Consumer<Object> consumer) {
consumers.add(consumer);
}
void invoke(Object sender) {
consumers.forEach(consumer -> {
System.out.println("sender ----> " + sender);
consumer.accept(sender);
});
}
}
public static class Rat {
private Game game;
Rat(Game game) {
this.game = game;
System.out.println("this ----> " + this);
game.ratEnters.subscribe((sender) -> System.out.println(this + " this ----> sender " + sender));
game.ratEnters.invoke(this);
}
}
public static class Game {
Event ratEnters = new Event();
}