2013-10-08 13 views
6

Ci sono domande simili ma non esattamente quello che voglio chiedere. Voglio chiedere come Iterator controlla la modifica.implementazione rapida iteratore

This link afferma che la sua implementazione è presente nella classe AbstractList dove è definito un modCount variabile int che fornisce il numero di volte in cui è stata modificata la dimensione dell'elenco. Questo valore viene utilizzato in ogni chiamata next() per verificare eventuali modifiche in una funzione checkForComodification().

Ma non riuscivo davvero a capirlo. Se il valore viene verificato solo dopo ogni chiamata successiva, se faccio una rimozione seguita da aggiungi nella stessa chiamata, la dimensione non cambierà e modCount non dovrebbe cambiare anche. Ma rimuovendo e aggiungendo nello stesso ciclo iterativo si genera anche un'eccezione.

risposta

8

Se si guarda il codice per un'implementazione Collection, scegliere ArrayList; abbiamo una variabile modCount dichiarata in AbstractList:

protected transient int modCount = 0; 

E poi in ogni metodo di modifica (ad esempio remove) per il ArrayList abbiamo

public E remove(int index) { 
    rangeCheck(index); 

    modCount++; 
    //.... 

Così l'modCount è sempre e solo incrementato ; è mai decrementato.

Nel Iterator abbiamo poi:

final void checkForComodification() { 
    if (modCount != expectedModCount) 
     throw new ConcurrentModificationException(); 
} 

Dove expectedModCount è un'istantanea della modCount prese a Iterator creazione.

Quindi, se non v'è alcuna modifica del sottostante List mentre la stessa istanza di un Iterator è in uso, allora viene generato un ConcurrentModificationException.

io ci credo è un caso d'angolo dove se effettuata abbastanza modifiche poi il int sarebbe traboccare e tornare al suo valore originale di nuovo - questo sarebbe un numero piuttosto grande o modifiche tuttavia; 2 per la precisione.

6

modCount aumenta sempre quando la lista viene modificata (quindi mod conteggio) quindi dovrebbe anche aumentare quando c'è una rimozione. Quindi aumenterebbe sia sulla rimozione che sull'aggiunta della chiamata.

Come Boris il ragno detto c'è il caso d'angolo che modCount overflow, si può vedere facendo:

List<Integer> nums = new ArrayList<>(); 
for(int i = 0; i < 10; i++) nums.add(i); 
for(int n : nums) { 
    System.out.println(n); 
    for(int i = -1; i < Integer.MAX_VALUE; i++) { 
     nums.add(i); 
     nums.remove(nums.size() - 1); 
    } 
} 

che sarà (lentamente) di stampa da 0 a 9 senza lanciare alcuna eccezione.

+0

+1, Funziona. Ma non è necessario presupporre che [il codice sia disponibile] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/util/AbstractList. java # AbstractList.0modCount). – yshavit

+0

@yshavit L'ho scritto prima di controllare il codice;) – Alowaniak

Problemi correlati