2010-03-10 22 views
24

Posso vedere che Collections.unmodifiableSet restituisce una vista non modificabile del set specificato ma non capisco perché non possiamo semplicemente usare il modificatore final per realizzare questo.Cosa fa Collections.unmodifiableSet() in Java?

A mio parere, final dichiara una costante: qualcosa che non può essere modificato. Quindi, se un set è dichiarato come costante, non può essere modificato: nulla può essere rimosso dal set e nulla può essere aggiunto.

Perché abbiamo bisogno di Collections.unmodifiableSet?

risposta

51

final dichiara un riferimento oggetto che non può essere modificato, ad es.

private final Foo something = new Foo(); 

crea un nuovo Foo e pone il riferimento in something.Successivamente, non è possibile modificare something in modo che punti a un'altra istanza di Foo.

Questo non impedisce la modifica dello stato interno dell'oggetto. Posso ancora chiamare qualsiasi metodo su Foo, sono accessibili per l'ambito pertinente. Se uno o più di questi metodi modifica lo stato interno di quell'oggetto, allora final non lo impedirà.

Come tale, il seguente:

private final Set<String> fixed = new HashSet<String>(); 

fa non creare un Set che non può essere inserito o altrimenti alterato; significa semplicemente che fixed farà sempre riferimento a tale istanza.

Al contrario, facendo:

private Set<String> fixed = Collections.unmodifiableSet(new HashSet<String>()); 

crea un'istanza di un Set, che getterà UnsupportedOperationException se si cerca di chiamare fixed.add() o fixed.remove(), per esempio - l'oggetto stesso proteggerà il suo stato interno ed evitare che si essere modificato.

Per completezza:

private final Set<String> fixed = Collections.unmodifiableSet(new HashSet<String>()); 

crea un'istanza di un Set che non consente il suo stato interno di essere cambiato, e significa anche che fixed sarà sempre solo puntare a un'istanza di tale insieme.

Il motivo per cui final può essere utilizzato per creare costanti di primitive si basa sul fatto che il valore non può essere modificato. Ricorda che fixed sopra era solo un riferimento - una variabile contenente un indirizzo che non può essere modificato. Bene, per i primitivi, ad es.

private final int ANSWER = 42; 

il valore di ANSWER è che ANSWER 42. Poiché non può essere modificato, sarà sempre e solo avere il valore 42.

Un esempio che confonde tutte le linee sarebbe questo:

private final String QUESTION = "The ultimate question"; 

Per le regole precedenti, QUESTION contiene l'indirizzo di un'istanza di String che rappresenta "La domanda finale" e che l'indirizzo non può essere modificato. La cosa da ricordare qui è che lo stesso String è immutabile: non è possibile eseguire alcuna operazione su un'istanza di String che lo modifica e qualsiasi operazione che altrimenti lo farebbe (come replace, substring, ecc.) Restituirà riferimenti completamente diversi istanze di String.

14

final garantisce solo che il riferimento all'oggetto rappresentato dalla variabile non possa essere modificato non faccia nulla per l'istanza dell'oggetto e la sua mutabilità.

final Set s = new Set(); garantisce solo che non è possibile eseguire nuovamente s = new Set();. Non rende il set non modificabile, se non si potesse aggiungere nulla all'inizio. Quindi, per renderlo veramente chiaro, final interessa solo la variabile riferimento non l'oggetto al quale punta il riferimento.

posso effettuare le seguenti operazioni:

final List<String> l = new ArrayList<String>(); 
l.add("hello"); 
l.add("world"); 
l.remove(0); 

ma non posso farlo.

l = new ArrayList<String>(); 

sempre a causa della final che non può modificare ciò le t punti variabili a.

è necessario eseguire una delle seguenti tre operazioni per rendere sicuro un thread del contenitore Collection.

java.util.Collections.syncronizedXXX(); 

o

java.util.Collections.unmodifiableXXX(); 

o uso uno degli appositi contenitori da java.util.concurrency.* package.

Se avessi un oggetto Person e ha fatto final Person p = new Person("me"); vuol dire che non posso riassegnare p per puntare a un altro oggetto Person. Posso ancora fare p.setFirstName("you");

Che confonde la situazione è che

final int PI = 3.14; 
final String greeting = "Hello World!"; 

apparire come const in C++, quando in realtà gli oggetti che puntano a sono immutabili/immodificabile dalla natura. Contenitori o oggetti con metodi di mutatore che possono alterare lo stato interno dell'oggetto non sono const solo il riferimento a quegli oggetti è final e non può essere riassegnato a riferimento un altro oggetto.

+1

Buon post. In breve, _reference_ non può essere modificato ma i _contents_ dell'oggetto * possono *. – extraneon

3

final non è (in stile C++) const. A differenza di C++, Java non ha metodi const o simili, e metodi che possono modificare l'oggetto possono essere richiamati tramite un riferimento final.

Collections.unmodifiable* è un wrapper che applica (in fase di esecuzione solo, non in fase di compilazione) la sola lettura per la raccolta interessata.

0

Il Collections.unmodifiableSet(Set<? extends T>) creerà il wrapper sul set originale. Questo set di wrapper non può essere modificato. ma ancora il set originale può essere modificato.

Esempio:

Set<String> actualSet=new HashSet<String>(); //Creating set 

Aggiunta alcuni elementi

actualSet.add("aaa"); 
actualSet.add("bbb"); 

stampa elementi

System.out.println(actualSet); //[aaa, bbb] 

Mettere il actualSet in serie immodificabile e assegnati al nuovo riferimento (wrapperSet) aggiunto.

Set<String> wrapperSet=Collections.unmodifiableSet(orginalSet); 

Stampa il wrapper Set. quindi avrà actualSet Valori

System.out.println(wrapperSet); //[aaa, bbb] 

Proviamo a rimuovere/aggiungere un elemento in wrapperSet.

wrapperSet.remove("aaa"); //UnSupportedOperationException 

aggiungere più un elemento actualSet

actualSet .add("ccc"); 

Stampa actualSet e wrapperSet. entrambi i valori impostati sono uguali. quindi Se aggiungi/rimuovi elementi sul set attuale le modifiche si rifletteranno anche sul set di wrapper.

System.out.println(actualSet); //[aaa, ccc, bbb] 
    System.out.println(wrapperSet); // [aaa, ccc, bbb] 

Usage:

Questo Collections.unmodifiableSet(Set<? extends T>) viene utilizzato per impedire la modifica del metodo getter del Set di qualsiasi oggetto. diciamo

public class Department{ 

    private Set<User> users=new HashSet<User>(); 

    public Set<User> getUsers(){ 
     return Collections.unmodifiableSet(users); 
    } 
}