2015-04-08 17 views
5

Quando si scava nella sorgente gs-collection per ImmutableList, non si estende java.util.List. Tuttavia, la classe javadoc ha affermato che le implementazioni di All ImmutableList devono implementare lo java.util.List.ImmutableList non estende l'elenco?

Perché richiedere l'implementazione per implementare java.util.List e non lo ImmutableList per estendere java.util.List?

+2

Cosa * fa * si estende? –

+1

Alla radice, estende 'java.lang.Iterable' – Wins

+0

Design strano. Invece di inserire un requisito inapplicabile in Javadoc, avrebbero potuto semplicemente scrivere 'extends java.util.Elenco e farlo applicare automaticamente. – EJP

risposta

11

Perché non ImmutableList estendere List?

ImmutableCollection non estende java.util.Collection (e ImmutableList non si estende java.util.List) perché Collection ha mutando metodi come add() e remove(). Se le collezioni immutabili avessero questi metodi, avrebbero sempre dovuto lanciare UnsupportedOperationException. Per gli utenti di collezioni immutabili, sarebbe strano vedere add() e remove() nelle scelte di completamento automatico come metodi chiamabili.

Perché Javadoc impone un contratto che tutte le implementazioni ImmutableList implementino anche List?

Si tratta di uguaglianza. Un ImmutableList deve essere uguale a List, assumendo che entrambi gli elenchi abbiano gli stessi contenuti nello stesso ordine. List.equals() imposes a Javadoc contract che afferma:

restituisce true se e solo se l'oggetto specificato è anche una lista, entrambi liste hanno le stesse dimensioni, e tutte le corrispondenti coppie di elementi a le due liste sono uguali.

Che cosa significa che "l'oggetto specificato è anche un elenco?" Possiamo vedere in AbstractList.equals() che significa instanceof List.

public boolean equals(Object o) { 
    if (o == this) 
     return true; 
    if (!(o instanceof List)) 
     return false; 
    ... 
} 

Così tutti ImmutableList implementazioni devono anche implementare List per equals() a lavorare in modo simmetrico. Le fabbriche di raccolta immutabili nascondono già dettagli di implementazione come il fatto che una lista immutabile con un singolo elemento è implementata da un ImmutableSingletonList. Si conclude anche nascondendo l'interfaccia List.

ImmutableList class diagram

Interop

Un vantaggio di questo progetto è che ImmutableList può essere gettato a List che è importante per l'interoperabilità con le API esistenti.

// Library method - cannot refactor the parameter type 
public void printAll(List<?> list) 
{ 
    for (Object each : list) 
    { 
     System.out.println(each); 
    } 
} 

ImmutableList<Integer> immutableList = Lists.immutable.with(1, 2, 3); 
List<Integer> castList = immutableList.castToList(); 
printAll(castList); 
// also works 
printAll((List<?>) immutableList); 

// throws UnsupportedOperationException 
castList.add(4); 

Nota: Sono uno sviluppatore su GS Collections.

+2

Grazie per la risposta lunga, ha senso, ma immagino che sia un sapore del design . Personalmente preferirei aggiungere() e remove() per lanciare UnsupportedOperationException piuttosto che chiamare castToList(). Lo sviluppatore dovrebbe sapere che se il codice utilizza ImmutableList, aggiungere e rimuovere non funzionerà e questo è il problema dello sviluppatore piuttosto che il problema del design. Ma credo che sia solo un'opinione personale. Grazie ancora per la risposta – Wins

+2

Penso che potresti essere interessato a UnmodifiableMutableList e al suo metodo factory MutableList.asUnmodifiable(). Ho mantenuto questa risposta limitata a ImmutableList ma mi sento libero di fare una nuova domanda sulle differenze e tornerò a scrivere di più. –

+2

Capisco UnmodifiableMutableList (il nome è molto esplicito), ma quello che sto chiedendo è perché non fare in modo che ImmutableList estenda List, lancia UnsupportedOperationException su add e remove, ma conserva l'immutabilità della lista e degli oggetti che contiene. – Wins