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
, и т. Д.) Возвращают ссылки на совершенно разные экземпляры String
.
Хороший пост. Короче говоря, _reference_ не может быть изменено, но _contents_ объекта * может *. – extraneon