Что делает Collections.unmodifiableSet (), делают в Java?

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

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

Почему нам нужно Collections.unmodifiableSet?

31
задан Michael 1 June 2017 в 18:27
поделиться

3 ответа

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

private final Foo something = new Foo();

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

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

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

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

не создает Набор , который нельзя добавить или изменить иным образом; это просто означает, что 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";

Согласно правилам, приведенным выше, ВОПРОС содержит адрес экземпляра String , который представляет «Главный вопрос», и этот адрес не может быть изменен. Здесь следует помнить, что String сам по себе неизменяемый - вы не можете ничего сделать с экземпляром String , который его изменяет, а также с любыми операциями, которые в противном случае сделали бы это (например, replace , substring и т. Д.) Возвращают ссылки на совершенно разные экземпляры String .

65
ответ дан 27 November 2019 в 21:40
поделиться

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

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

3
ответ дан 27 November 2019 в 21:40
поделиться

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.

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

java.util.Collections.syncronizedXXX();

,

java.util.Collections.unmodifiableXXX();

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

если у меня был объект Person и я сделал final Person p = new Person («я»); это означает, что я не могу переназначить p на указать на другой объект Person . Я все еще могу сделать p.setFirstName ("you");

Ситуацию смущает то, что

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

в C ++ выглядит как const , тогда как на самом деле объекты, на которые они указывают, являются неизменный / неизменяемый по своей природе. Контейнеры или объекты с методами мутатора, которые могут изменять внутреннее состояние объекта, не const , просто ссылка на эти объекты являются окончательными и не могут быть переназначены к ссылка на другой объект.

15
ответ дан 27 November 2019 в 21:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: