我不理解此代码的基本原理,取自javax.swing.event.EventListenerList docs:
protected void fireFooXXX() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==FooListener.class) {
// Lazily create the event:
if (fooEvent == null)
fooEvent = new FooEvent(this);
((FooListener)listeners[i+1]).fooXXX(fooEvent);
}
}
}
事件触发在javax.swing.tree.DefaultTreeModel等中以这种方式实现,所以显然我只是没有得到什么。
答案 0 :(得分:6)
在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));
触发事件将提供以下输出:
0
1
3
我们将通过索引从0到3循环遍历侦听器。在索引1处,侦听器将自己从侦听器的内部数组中移除,从而使侦听器2和3向下移动到索引1和2.循环继续索引2现在包含侦听器3.已跳过侦听器2。
通过向后迭代,这个问题被消除了,因为删除一个监听器只会改变已经被调用的监听器的索引。
但是
EventListenerList没有此问题,因为add()和remove()方法是copy-on-write,并且建议用法中的侦听器遍历在循环之前对getListenerList()返回的侦听器列表实例进行操作。 / p>
有关它的更多讨论可以在this thread中找到,其原因似乎归结为:
性能
事件排序(最后添加的侦听器将是第一个被通知的人)
akf和Michael Borgwardt已经回答说EvenListenerList除了监听器之外还存储了监听器类型。我想这是因为它使单个EventListenerList可以处理不同类型的侦听器。
答案 1 :(得分:5)
答案 2 :(得分:3)
回答#2:调用每个第二个侦听器,因为EventListenerList使用的数组被设置为一个Listener-Type,Listener-Instance对的数组。