Что делает коллекции.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