以下代码取自Oracle jdk1.8.0_40 AbstractListModel类。
/**
* <code>AbstractListModel</code> subclasses must call this method
* <b>after</b>
* one or more elements of the list change. The changed elements
* are specified by the closed interval index0, index1 -- the endpoints
* are included. Note that
* index0 need not be less than or equal to index1.
*
* @param source the <code>ListModel</code> that changed, typically "this"
* @param index0 one end of the new interval
* @param index1 the other end of the new interval
* @see EventListenerList
* @see DefaultListModel
*/
protected void fireContentsChanged(Object source, int index0, int index1)
{
Object[] listeners = listenerList.getListenerList();
ListDataEvent e = null;
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ListDataListener.class) {
if (e == null) {
e = new ListDataEvent(source, ListDataEvent.CONTENTS_CHANGED, index0, index1);
}
((ListDataListener)listeners[i+1]).contentsChanged(e);
}
}
}
我的问题是
listeners.length - 2
开始listeners.length - 1
元素呢?i -= 2
)触发事件?指向code in openjdk的链接。
答案 0 :(得分:6)
listeners
数组包含听众&#39;偶数索引中的Class
个对象和奇数索引中的侦听器实例。
因此循环检查listeners
数组
if (listeners[i] == ListDataListener.class
但仅针对奇数索引触发事件:
((ListDataListener)listeners[i+1]).contentsChanged(e);
不会跳过 listeners.length - 1
。从i == listeners.length - 2
,i+1 == listeners.length - 1
开始。
我不确定逆序迭代的原因。
答案 1 :(得分:1)
根据add a new listener的代码,如下所示:
public void addListDataListener(ListDataListener l) {
listenerList.add(ListDataListener.class, l);
}
列表实际上包含Class
个实例和对象实例对。
关于迭代顺序,或许首先是通知新型侦听器的故意方法?
答案 2 :(得分:1)
如果查看EventListenerList:列表是使用两个元素构建的,其中一个是侦听器对象,另一个是对象的类。这解释了2-by-2迭代以及与另一个元素对一个类的检查。
我发现这段代码非常难看,很多重复这个奇怪的迭代循环。 我没有得到关于这个相当严格的实现的答案,但IMO的原因可能是保持与传统JAVA的兼容性 - 保持API相同,也许是性能,可能是在Java 1.5中引入泛型。 / p>
Wy以相反的顺序迭代? 不知道为什么它会这样实现。可能是实现决策或需要首先调用最新添加的侦听器的规范。 我试图找到另一个很好的理由,但我不能......而且它曾经反向迭代,因为至少1.6(我没有检查旧版本)。
答案 3 :(得分:1)
他们以相反顺序重复的原因是他们不必每次都评估.length
。他们将其作为性能优化。 Here's a related question.