Коллекции.немодифицируемыеЛист и защитная копия
Если я пишу
List<Integer> a1 = Arrays.asList(1, 2, 3);
List<Integer> a2 = Collections.unmodifiableList(a1);
a2
доступен только для чтения, но если я пишу
a1.set(0,10);
то a2
также изменяется.
Если в API сказано:
Возвращает немодифицируемое представление указанной коллекции. Этот метод позволяет модулям предоставлять пользователям доступ только для чтения к внутренним коллекции.
то почему, если я изменяю исходную коллекцию, также изменяется измененная копия коллекции?
Возможно, я неправильно понял смысл, и если да, то каким образом
написать защитную копию этой коллекции?
Ответы
Ответ 1
Да, вы поняли это правильно. Идея состоит в том, что объект, возвращаемый umodifiableCollection
, не может быть напрямую изменен, но может измениться с помощью других средств (эффективно, напрямую изменив внутреннюю коллекцию).
До тех пор, пока что-то имеет доступ ко внутреннему списку, можно изменить "немодифицируемую" коллекцию.
Вот почему вы обычно строите немодифицируемую коллекцию и убедитесь, что ничто не может попасть во внутренний список:
Collection<Integer> myUmodifiableCollection = Collection.umodifiableCollection(Arrays.asList(1, 2, 3));
Поскольку ничто никогда не получает ссылку на List
, созданную asList
, это действительно немодифицируемая коллекция.
Преимущество этого подхода в том, что вам не нужно вообще копировать исходный список/список, что позволяет избежать использования памяти и вычислительной мощности.
Guava предоставляет класс ImmutableCollection
(и его подклассы, такие как ImmutableList
), которые предоставляют настоящие неизменные коллекции (обычно путем копирования источника).
Ответ 2
Возможно, я неправильно понял смысл, и если да, то как писать защитную копию этой коллекции?
Как правило, вы должны использовать его таким образом:
private List<Integer> a1 = Arrays.asList(1, 2, 3);
public List<Integer> getUnmodifiable() {
return Collections.unmodifiableList(a1);
}
Кто-то, кто называет getUnmodifiable
и, не имеет доступа к внутреннему классу вашего класса (то есть не может получить доступ к частной переменной a1
), не сможет изменить возвращенный список.
Ответ 3
Идея состоит в том, что вы не можете изменить список через a2
.
Изменение списка a1
действительно изменит то, что вы видите в a2
- это предназначено.
Просто у вас нет общедоступного доступа к списку a1
, и вы должны иметь то, что хотите:
Ответ 4
API говорит, что внутренние коллекции в вашем случае коллекция не является внутренней
Дело в том, что, когда у вас есть закрытый список в классе, а gettet для этого списка, вы можете захотеть, чтобы вызывающие абоненты не смогли изменить список в случае с вами, вам нужно будет вернуть список, подлежащий учету, в противном случае возвращенный список будет просто ссылкой на ваш внутренний/закрытый список и, следовательно, его содержимое может быть изменено.
Ответ 5
Заявление:
Collections.unmodifiableList(a1);
возвращает обертку поверх исходной коллекции, методы модификатора которой выбрасывают UnsupportedOperationException
.
Обертка является сквозной, что означает, что если вы измените a1
, изменения отразятся на завернутой коллекции a2
.
Ответ 6
a1
и a2
будут ссылаться на одни и те же данные (память).
появляется немонизируемая часть, только с a2
в качестве записи.
если вы передаете a2
методу, в котором вы ожидаете, что метод будет идемпотентом. такие случаи a2
помогают.
вы не можете изменять данные с помощью указателя a2
.
Ответ 7
Если вам нужен немодифицируемый и неизменный список или, другими словами, неизменяемая копия исходного списка без какой-либо зависимости с другими библиотеками, попробуйте следующее:
Collections.unmodifiableList(Collections.list(Collections.enumeration(sourceList)))
Collections.list()
копирует значения из его перечисления.