Rückiteration bei der EventListenerList

bene2808

Aktives Mitglied
Hallo,

bin vor kurzem über ein Thema gestolpert, das mich etwas verwirrt hat, nämlich die EventListenerList und vor Allem deren korrekte Verwendung. Habe auf Anhieb keine meine Frage beantwortenden Posts "ergoogeln" können, deswegen frage ich hier.

Die Java Swing Klassen rufen die einzelnen Listener vom letzten Element in der Liste bis zum vorderen auf, mit der Begründung, dass bei einer eventuellen Löschung eines Listeners durch sich selbst kein Element übersprungen wird.
Aber: Wenn man tatsächlich nur einmal das Array am Anfang seiner fireWasAuchImmer-Methode von der EventListenerList erfragt (so wie es zum Beispiel der JSlider macht), ist die Instanz ja spätestens dann nicht mehr up to date, wenn ein Listener sich selbst löscht, denn dann wird in der EventListenerList das Array neu initialisiert, was dann aber nicht mehr die lokale Referenz betrifft. Somit ist dass Rückwärts-Durchlaufen doch vollkommen unnötig, oder ??? :autsch: (Abgesehen vom dem Fakt, von dem ich iwo gehört habe, dass ein Vergleich mit 0 bei der Abbruchbedingung iwie hardwarebeschleunigt ablaufen soll, was aber vmtl. vernachlässigt werden darf :))

Ist mir bloß aufgefallen und ich wollte wissen, ob ich tatsächlich rückwärts durchlaufen muss, was ich allgemein ein wenig verwirrender finde, oder ob die Alternative, das Durchlaufen vorwärts, ebenso "unbedenklich" ist.
 

bene2808

Aktives Mitglied
Quelle für die Überlegung an sich? Naja, ich hab mir den Quellcode von EventListenerList und JSlider angeschaut :). Oder Quelle wofür meinst du?

EventListenerList gibt das interne Array (und zwar nicht als Kopie) zurück:
Code:
/**
 * Passes back the event listener list as an array
 * of ListenerType-listener pairs.  Note that for
 * performance reasons, this implementation passes back
 * the actual data structure in which the listener data
 * is stored internally!
 * This method is guaranteed to pass back a non-null
 * array, so that no null-checking is required in
 * fire methods.  A zero-length array of Object should
 * be returned if there are currently no listeners.
 *
 * WARNING!!! Absolutely NO modification of
 * the data contained in this array should be made -- if
 * any such manipulation is necessary, it should be done
 * on a copy of the array returned rather than the array
 * itself.
 */
 public Object[] getListenerList() {
     return listenerList;
 }

EventListenerList löscht einen Listener. Das Array wird verkleinert, oder besser: ein neues verkleinertes erstellt:
Code:
/**
 * Removes the listener as a listener of the specified type.
 * @param t the type of the listener to be removed
 * @param l the listener to be removed
 */
public synchronized <T extends EventListener> void remove(Class<T> t, T l) {
    if (l ==null) {
        // In an ideal world, we would do an assertion here
        // to help developers know they are probably doing
        // something wrong
        return;
    }
    if (!t.isInstance(l)) {
        throw new IllegalArgumentException("Listener " + l +
                                     " is not of type " + t);
    }
    // Is l on the list?
    int index = -1;
    for (int i = listenerList.length-2; i>=0; i-=2) {
        if ((listenerList[i]==t) && (listenerList[i+1].equals(l) == true)) {
            index = i;
            break;
        }
    }
    // If so,  remove it
    if (index != -1) {
        Object[] tmp = new Object[listenerList.length-2];
        // Copy the list up to index
        System.arraycopy(listenerList, 0, tmp, 0, index);
        // Copy from two past the index, up to
        // the end of tmp (which is two elements
        // shorter than the old list)
        if (index < tmp.length)
            System.arraycopy(listenerList, index+2, tmp, index,
                             tmp.length - index);
        // set the listener array to the new array or null
        listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp;
    }
}

Und hier der Codeschnipsel aus der JSlider-Klasse, der exemplarisch für die meisten anderen Komponenten sein sollte:
Code:
/**
 * Send a {@code ChangeEvent}, whose source is this {@code JSlider}, to
 * all {@code ChangeListener}s that have registered interest in
 * {@code ChangeEvent}s.
 * This method is called each time a {@code ChangeEvent} is received from
 * the model.
 * <p>
 * The event instance is created if necessary, and stored in
 * {@code changeEvent}.
 *
 * @see #addChangeListener
 * @see EventListenerList
 */
protected void fireStateChanged() {
    Object[] listeners = listenerList.getListenerList();
    for (int i = listeners.length - 2; i >= 0; i -= 2) {
        if (listeners[i]==ChangeListener.class) {
            if (changeEvent == null) {
                changeEvent = new ChangeEvent(this);
            }
            ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
        }
    }
}

Die Instanz wird am Anfang ermittelt und kann somit nicht aktuell sein, wenn sich die Länge des EventListenerList internen Arrays ändert, da sie auf das alte Array verweist.

PS: Sorry für so viel Code, aber ich dachte ein Haufen verständlicher Code ist besser als die schlichte Frage, welche Quellen denn gemeint sind :).
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
KrokoDiehl EventListenerList vs. ArrayList AWT, Swing, JavaFX & SWT 3

Ähnliche Java Themen

Neue Themen


Oben