Подтвердить что ты не робот

Коллекции.немодифицируемыеЛист и защитная копия

Если я пишу

List<Integer> a1 = Arrays.asList(1, 2, 3);
List<Integer> a2 = Collections.unmodifiableList(a1);

a2 доступен только для чтения, но если я пишу

a1.set(0,10);

то a2 также изменяется.

Если в API сказано:

Возвращает немодифицируемое представление указанной коллекции. Этот метод позволяет модулям предоставлять пользователям доступ только для чтения к внутренним коллекции.

то почему, если я изменяю исходную коллекцию, также изменяется измененная копия коллекции?

Возможно, я неправильно понял смысл, и если да, то каким образом написать защитную копию этой коллекции?

4b9b3361

Ответ 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() копирует значения из его перечисления.