Что делает коллекции.unmodifiableSet () делать на Java?

Я вижу Collections.unmodifiableSet возвращает неподдающееся изменению представление данного набора, но я не понимаю, почему мы не можем просто использовать final модификатор для этого.

в моем понимании, final объявляется константа: что-то, что нельзя изменить. Таким образом, если набор объявлен константой, он не может быть изменен: из набора ничего нельзя удалить и ничего нельзя добавить.

зачем это нужно Collections.unmodifiableSet?

5 ответов


final объявляет ссылку на объект, которая не может быть изменена, например

private final Foo something = new Foo();

создает новый Foo и помещает ссылку в something. После этого невозможно изменить something указать на другой экземпляр Foo.

это не запретить изменение внутреннего состояния объекта. Я все еще могу вызвать любые методы на Foo доступны для соответствующей области. Если один или несколько из этих методов изменяет внутреннее состояние этого объекта, затем final не допустить этого.

таким образом, следующее:

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

тут не создать Set это не может быть добавлено или иным образом изменено; это просто означает, что fixed будет ссылаться только на этот экземпляр.

напротив, делает:

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

создает экземпляр Set будут UnsupportedOperationException если попытаться вызвать fixed.add() или fixed.remove(), для пример - сам объект будет защищать свое внутреннее состояние и предотвратить его изменения.

для полноты картины:

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

создает экземпляр Set что не позволит изменить его внутреннее состояние, а также означает, что fixed будет указывать только на экземпляр этого набора.

причина final может использоваться для создания констант примитивов на основе того, что значение не может быть изменено. Помнить это fixed выше была просто ссылка-переменная, содержащая адрес, который нельзя изменить. Ну, для примитивов, например,

private final int ANSWER = 42;

значение ANSWER это 42. С ANSWER не может быть изменен, он будет иметь только значение 42.

пример, который размывает все строки, будет следующим:

private final String QUESTION = "The ultimate question";

по правилам выше,QUESTION содержит адрес экземпляра String который представляет собой "окончательный вопрос", и этот адрес его нельзя изменить. Здесь следует помнить, что String сам по себе неизменен - вы ничего не можете сделать с экземпляром String который изменяет его, и любые операции, которые в противном случае сделали бы это (например,replace, substring, etc.) возврат ссылок на совершенно разные экземпляры String.


final только гарантий, что ссылка объект, который представляет переменная, не может быть изменен, он ничего не делает для экземпляра объекта и его изменчивости.

final Set s = new Set(); просто гарантирует, что вы не можете сделать s = new Set(); снова. Это не делает набор немодифицируемым, если бы вы ничего не могли добавить к нему для начала. Поэтому, чтобы сделать это действительно ясно,final влияет только на переменную ссылка не объект точки отсчета к.

Я могу сделать следующее:

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

но я не могу этого сделать.

l = new ArrayList<String>();

снова из-за final Я не могу изменить то, на что указывает переменная l.

вы должны сделать одну из следующих трех вещей, чтобы сделать поток контейнера коллекции безопасным.

java.util.Collections.syncronizedXXX();

или

java.util.Collections.unmodifiableXXX();

или используйте один из соответствующих контейнеров из java.util.concurrency.* package.

если бы у меня был


final не является (C++-style) const. В отличие от C++, Java не имеют const - методы или что-то подобное, и методы, которые могут изменить объект, могут быть вызваны через final ссылка.

Collections.unmodifiable* - это оболочка, которая обеспечивает (только во время выполнения, а не во время компиляции) только чтение для соответствующей коллекции.


на Collections.unmodifiableSet(Set<? extends T>) создаст обертку на исходном наборе. Этот набор обертки не может быть изменен. но все же исходный набор можно изменить.

пример:

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

добавление некоторых элементов

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

печать добавленных элементов

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

поставить actualSet в немодифицируемый набор и назначен новой ссылке (wrapperSet).

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

печать wrapperSet. так что придется actualSet Значения

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

давайте попробуем удалить/добавить один элемент на wrapperSet.

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

добавить еще один элемент в actualSet

    actualSet .add("ccc");

печати actualSet и wrapperSet. значения обоих наборов одинаковы. поэтому, если вы добавляете / удаляете какие-либо элементы в фактическом наборе, изменения будут отражены и в наборе обертки.

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

использование:

этой Collections.unmodifiableSet(Set<? extends T>) используется для предотвращения изменения метода геттера Set любого объекта. позволять скажи

public class Department{

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

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

суммируем, что мы можем сделать и не можем:

Приготовление:

private Set<String> words = new HashSet<>(Arrays.asList("existing word"));

финал по ссылке

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

can:

words.add("new word");

не могу:

words = new HashSet<>(); //compilation error

окончательный по ссылке и неизменяемый по коллекции.

частный окончательный набор слов = коллекции.unmodifiableSet(слова);

can:

String word = words.iterator().next();

не могу:

words = new HashSet<>(); // compilation error
words.add("new word"); // runtime error UnsupportedOperationException

окончательный по ссылке и неизменяемый по коллекции, но взаимный как объект коллекции.

но если у вас есть коллекции с взаимный объекты вы можете изменить внутреннее состояние этого объекта.

 class A {
       public int a; //mutable field. I can change it after initialization
       public A(int a) {this.a = a;}
     }

 private final Set<A> set = Collections.unmodifiableSet(Arrays.asList(new A(25)));

все еще не могу

set = new HashSet<>(); // compilation error
set.add(new A(777)); // runtime error UnsupportedOperationException

но

 A custom = words.iterator().next(); //here custom.a = 25;
 custom.a = 777; //here first element of **final, unmodifible** collection 
    //was changed from 25 to 777