Почему EventListenerList пересечен назад в fireFooXXX ()?

Правила для определенного присвоения являются довольно трудными (глава 16 чтения 3-го Ed JLS). Это не практично для осуществления определенного присвоения на полях. В настоящий момент даже возможно наблюдать заключительные поля, прежде чем они будут инициализированы.

6
задан Joonas Pulakka 31 May 2010 в 04:40
поделиться

3 ответа

  1. Вероятно, из соображений производительности: обратная итерация выполняется быстрее, потому что сравнение с 0 - это единственная инструкция машинного кода - многие бывшие программисты на C это укоренили, хотя сейчас это неактуально. Обратите внимание, что нет никакой гарантии относительно порядка, в котором слушатели будут уведомлены в любом случае.
  2. Посмотрите на остальную часть класса - он также хранит типы слушателей для обеспечения безопасности типов.
5
ответ дан 8 December 2019 в 17:23
поделиться

для ответа №2: Каждый второй прослушиватель вызывается, потому что массив, который использует EventListenerList, заполняется как массив пар "слушатель-тип", "слушатель-экземпляр".

3
ответ дан 8 December 2019 в 17:23
поделиться

1.

Одна из возможных проблем при обходе слушателей описана в 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 () перед петля.

Еще несколько дискуссий по этому поводу можно найти в этой ветке , где причины, кажется, сводятся к одному из:

  • производительность

  • упорядочение событий (последний добавленный слушатель будет первым быть уведомленным)


2.

akf и Майкл Боргвардт уже ответили, что EvenListenerList хранит типы слушателей в дополнение к слушателям.Я предполагаю, что причина этого в том, что он позволяет одному EventListenerList обрабатывать слушатели разных типов.

6
ответ дан 8 December 2019 в 17:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: