2010-03-10 26 views
24

Widzę, że Collections.unmodifiableSet zwraca niezmodyfikowany widok danego zestawu, ale nie rozumiem, dlaczego nie możemy po prostu użyć modyfikatora final, aby to osiągnąć.Co robi Collections.unmodifiableSet() w Javie?

W moim rozumieniu final deklaruje stałą: coś, czego nie można zmodyfikować. Tak więc, jeśli zbiór jest zadeklarowany jako stała, to nie można go zmienić: nic nie można usunąć z zestawu i nic nie można dodać.

Dlaczego potrzebujemy Collections.unmodifiableSet?

Odpowiedz

51

final Deklaruje odniesienie do obiektu, którego nie można zmodyfikować, np.

private final Foo something = new Foo(); 

tworzy nowy Foo i umieszcza odniesienie w something.Następnie nie można zmienić something, aby wskazać inne wystąpienie Foo.

To robi nie zapobiec modyfikacji wewnętrznego stanu obiektu. Nadal mogę zadzwonić, niezależnie od metody na Foo są dostępne dla odpowiedniego zakresu. Jeśli jedna lub więcej z tych metod modyfikuje stan wewnętrzny tego obiektu, to nie zapobiegnie to.

Jako takie, następujące:

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

nie nie utworzyć Set, które nie mogą być dodawane do lub w inny sposób zmianom; oznacza to tylko, że fixed będzie tylko odwoływać się do tej instancji.

Natomiast robi:

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

tworzy instancję Set który rzuci UnsupportedOperationException jeśli ktoś próbuje zadzwonić fixed.add() lub fixed.remove(), na przykład - sam obiekt będzie chronić swój stan wewnętrzny i uniemożliwić być modyfikowanym.

Dla dobra kompletności:

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

tworzy instancję Set który nie pozwoli jej stan wewnętrzny może zostać zmieniona, a także oznacza, że ​​fixed będzie zawsze tylko wskazywać na wystąpienie tego zestawu.

Powodem, dla którego final można użyć do utworzenia stałych prymitywów, jest fakt, że wartości nie można zmienić. Pamiętaj, że powyższa fixed była tylko referencją - zmienną zawierającą adres, którego nie można zmienić. Cóż, dla prymitywów, np.

private final int ANSWER = 42; 

wartość ANSWER jest 42. Od ANSWER nie mogą być zmieniane, to tylko kiedykolwiek miał wartość 42.

przykład, który zaciera wszystkie linie będzie to:

private final String QUESTION = "The ultimate question"; 

Zgodnie z powyższymi regułami, QUESTION zawiera adres instancji String, która stanowi "Ostateczne pytanie", którego adresu nie można zmienić. Należy pamiętać, że sama nazwa String jest niezmienna - nie można nic zrobić z instancją String, która zmienia ją, a wszelkie operacje, które w przeciwnym wypadku byłyby wykonywane (np. replace, substring itd.), Zwracają odwołania do zupełnie innych wystąpienia String.

14

final gwarantuje jedynie, że odniesienie do obiektu, którego reprezentuje zmienna, nie może być zmieniony, nie robi nic dla instancji obiektu i jego zmienności.

final Set s = new Set(); tylko gwarancje, że nie można ponownie wykonać s = new Set();. Nie sprawia, że ​​zestaw nie może być modyfikowany, jeśli nie można na nim nic dodać. Aby było to naprawdę jasne, parametr wpływa tylko na obiekt, do którego odnosi się odniesienie.

mogę wykonać następujące czynności:

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

ale nie mogę tego zrobić.

l = new ArrayList<String>(); 

ponownie ze względu na final nie mogę modyfikować jaka zmienne punkty l do.

Musisz wykonać jedną z następujących trzech czynności, aby zabezpieczenie pojemnika zbiorczego było bezpieczne.

java.util.Collections.syncronizedXXX(); 

lub

java.util.Collections.unmodifiableXXX(); 

lub wykorzystanie jednego z odpowiednich pojemników z java.util.concurrency.* package.

gdybym miał Person przedmiot i zrobił final Person p = new Person("me"); to znaczy, że nie można przypisać p aby wskazać inną Person obiektu. Wciąż mogę zrobić p.setFirstName("you");

Co myli sytuacji jest to, że

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

wyglądać const w C++, podczas gdy w rzeczywistości obiekty, które wskazują one są niezmienne/niezmienne przez naturę. Kontenery lub obiekty z metodami mutatora, które mogą zmieniać wewnętrzny stan obiektu, nie są tylko tymi obiektami, które są i nie można ich ponownie przypisać do innego obiektu.

+1

Dobra wiadomość. W skrócie, _reference_ nie może być zmieniony, ale _contents_ obiektu * może *. – extraneon

3

final nie jest (C++ - styl) const. W przeciwieństwie do języka C++, Java nie ma metod, ani niczego w tym stylu, a metody, które mogą zmienić obiekt, można wywoływać za pośrednictwem odwołania o numerze: final.

Collections.unmodifiable* to opakowanie, które wymusza (tylko w czasie wykonywania, a nie w czasie kompilacji) tylko do odczytu dla danego zbioru.

0

Urządzenie Collections.unmodifiableSet(Set<? extends T>) utworzy opakowanie w oryginalnym zestawie. Tego zestawu opakowań nie można zmodyfikować. ale wciąż oryginalny zestaw można zmodyfikować.

przykład:

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

Dodanie kilku elementów

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

druku dodaje elementy

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

PUT actualSet się żadnych modyfikacji zbioru i przypisane do nowego odniesienia (wrapperSet).

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

Wydrukuj wrapperSet. więc będzie mieć actualSet wartości

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

Spróbujmy usunąć/dodać jeden element na wrapperSet.

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

Dodaj jeszcze jeden element actualSet

actualSet .add("ccc"); 

Drukuj actualSet i wrapperSet. obie ustawione wartości są takie same. więc jeśli dodasz/usuniesz jakiekolwiek elementy na rzeczywistym zestawie, zmiany zostaną również odzwierciedlone w zestawie opakowania.

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

Zastosowanie:

Ten Collections.unmodifiableSet(Set<? extends T>) jest stosowany w celu zapobiegania modyfikację Seta metody pochłaniacza dowolnego obiektu. powiedzmy:

public class Department{ 

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

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