Правила для определенного присвоения являются довольно трудными (глава 16 чтения 3-го Ed JLS). Это не практично для осуществления определенного присвоения на полях. В настоящий момент даже возможно наблюдать заключительные поля, прежде чем они будут инициализированы.
для ответа №2: Каждый второй прослушиватель вызывается, потому что массив, который использует EventListenerList, заполняется как массив пар "слушатель-тип", "слушатель-экземпляр".
Одна из возможных проблем при обходе слушателей описана в Swing Hacks , пункт № 94, и возникает, если один из них удаляет себя как слушатель в своей реализации fooXXX ().
Рассмотрим этот слушатель, который может удалить себя после получения события:
public class FooListener implements EventListener {
private int i;
public FooListener(int i) {
this.i = i;
}
public fooXXX(FooEvent foo) {
System.out.println(i);
if (i == 1) {
((FooEventSource)foo.getSource()).removeListener(this);
}
}
}
и эту реализацию обхода слушателя:
public void fireFooXXX() {
for (int i=0; i<listeners.size(); i++) {
// Lazily create the event:
if (fooEvent == null)
fooEvent = new FooEvent(this);
listeners.get(i).fooXXX(fooEvent);
}
}
Теперь предположим, что мы создаем несколько таких слушателей:
fooEventSource.addListener(new FooListener(0));
fooEventSource.addListener(new FooListener(1));
fooEventSource.addListener(new FooListener(2));
fooEventSource.addListener(new FooListener(3));
Запуск события даст следующее output:
0
1
3
Мы будем перебирать слушателей по индексу от 0 до 3. При индексе 1 слушатель удаляется из внутреннего массива слушателей, в результате чего слушатели 2 и 3 смещаются вниз к индексам 1 и 2. цикл продолжается с индексом 2, который теперь содержит слушателя 3. Слушатель 2 был пропущен.
Повторение в обратном направлении устраняет эту проблему, поскольку удаление слушателя приведет только к смещению индекса уже вызванных слушателей.
Но
EventListenerList не имеет этой проблемы, поскольку методы add () и remove () являются методами копирования при записи, а обход слушателя в предлагаемом использовании работает с экземпляром списка слушателей, возвращенным getListenerList () перед петля.
Еще несколько дискуссий по этому поводу можно найти в этой ветке , где причины, кажется, сводятся к одному из:
производительность
упорядочение событий (последний добавленный слушатель будет первым быть уведомленным)
akf и Майкл Боргвардт уже ответили, что EvenListenerList хранит типы слушателей в дополнение к слушателям.Я предполагаю, что причина этого в том, что он позволяет одному EventListenerList обрабатывать слушатели разных типов.