Swing 为什么在fireFooXXX()中向后遍历EventListenerList?

Swing 为什么在fireFooXXX()中向后遍历EventListenerList?,swing,java,event-listener,Swing,Java,Event Listener,我不理解这段代码的基本原理,摘自文档: 为什么列表被向后遍历 为什么只调用第二个侦听器 事件触发就是以这种方式实现的,因此显然是我没有得到任何东西。回答#2:每秒调用一个侦听器,因为EventListenerList使用的数组被设置为侦听器类型、侦听器实例对的数组 可能是性能方面的考虑:向后迭代速度更快,因为与0相比,它是一条机器代码指令——许多以前的C程序员都有这种根深蒂固的习惯,尽管现在这种习惯已经不再适用了。请注意,无论如何都不能保证通知侦听器的顺序 看看这个类的其余部分——它还存储侦听器

我不理解这段代码的基本原理,摘自文档:

  • 为什么列表被向后遍历
  • 为什么只调用第二个侦听器
  • 事件触发就是以这种方式实现的,因此显然是我没有得到任何东西。

    回答#2:每秒调用一个侦听器,因为EventListenerList使用的数组被设置为侦听器类型、侦听器实例对的数组

  • 可能是性能方面的考虑:向后迭代速度更快,因为与0相比,它是一条机器代码指令——许多以前的C程序员都有这种根深蒂固的习惯,尽管现在这种习惯已经不再适用了。请注意,无论如何都不能保证通知侦听器的顺序
  • 看看这个类的其余部分——它还存储侦听器的类型,以提供类型安全性
  • 1. 第#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);
       }
    }
    
    触发事件将产生以下输出:

    0
    1
    3
    
    我们将按索引在侦听器上循环,从0到3。在索引1处,侦听器将自己从侦听器的内部数组中移除,导致侦听器2和3下移到索引1和2。循环继续进行,索引2现在包含侦听器3。已跳过侦听器2

    通过向后迭代,可以消除此问题,因为删除侦听器只会移动已调用的侦听器的索引

    但是

    EventListenerList没有这个问题,因为add()和remove()方法是写时复制的,并且建议用法中的侦听器遍历操作在循环之前由getListenerList()返回的侦听器列表实例上进行

    关于它的更多讨论可以在中找到,其中的原因似乎归结为:

    • 演出

    • 事件顺序(最后添加的侦听器将是第一个收到通知的侦听器)


    2.
    akf和Michael Borgwardt已经回答说,EvenListenerList除了保存侦听器之外,还存储侦听器类型。我想这是因为它使单个EventListenerList可以处理不同类型的侦听器。

    啊,好的。我只是想知道为什么它不是像
    doublistener[]listener=listenerList.getListeners(doublistener.class)
    那样编写的。会干净一点的,伊姆霍。也许这也与性能有关。我认为注释中的代码示例已经过时了-getListeners()方法是在Java 1.3中添加的,可能是因为他们想先通知最后一个侦听器才这样做?@Suraj Chandran没有理由想要这样的东西,通知顺序不明确你没有试过,是吗?只要您遵循api文档中的示例并简单地反转循环方向,即在循环之前抓住侦听器数组一次,这是错误的:字段侦听器在add/RemovelListener上被重新分配,本地引用不够有效,我没有。。。我已经相应地更新了答案,但是我留下了在迭代侦听器列表时可能出现的问题的描述。谢谢你纠正了我的错误。酷-你挖到了ol'线程,没有想到java.net论坛上会有任何东西是可以找到的:-)从这一点和其他线程中要吸取的要点是a)通知顺序是未指定的,这不重要,因为侦听器不能依赖任何序列b)所有侦听器都是平等的,也就是说,他们必须(并且)独立于(awt)事件是否被使用而得到通知
    fooEventSource.addListener(new FooListener(0));
    fooEventSource.addListener(new FooListener(1));
    fooEventSource.addListener(new FooListener(2));
    fooEventSource.addListener(new FooListener(3));
    
    0
    1
    3