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