Collections.unmodifiableList и защитная копия

Если я напишу

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

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

a1.set(0,10);

затем a2 также модифицируется.

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

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

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

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

9 ответов

Решение

Да, вы правильно поняли. Идея в том, что объект возвращается umodifiableCollection не может быть изменен напрямую, но может измениться с помощью других средств (фактически путем непосредственного изменения внутренней коллекции).

Пока что-то имеет доступ к внутреннему списку, "немодифицируемая" коллекция может быть изменена.

Вот почему вы обычно создаете неизменяемую коллекцию и следите за тем, чтобы ничто не могло попасть во внутренний список:

Collection<Integer> myUmodifiableCollection = Collection.umodifiableCollection(Arrays.asList(1, 2, 3));

Так как ничто никогда не получает ссылку на List создано asListЭто действительно неизменяемая коллекция.

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

Гуава обеспечивает ImmutableCollection класс (и его подклассы, такие как ImmutableList) которые предоставляют истинные неизменные коллекции (обычно путем копирования источника).

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

Как правило, вы бы использовали это так:

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

public List<Integer> getUnmodifiable() {
    return Collections.unmodifiableList(a1);
}

Кто-то, кто звонит getUnmodifiable и не имеет доступа к внутренней части вашего класса (т.е. они не могут получить доступ к закрытой переменной a1), не сможет изменить возвращенный список.

Если вы хотели сохранить a1 изменяемый и сделать его неизменным без Гуавы, это один из способов сделать это.

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

Начиная с Java 10 вы можете:

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

После этого меняется на a1не видны сквозь a2, потому что List.copyOf()копирует содержимое вашего списка в новый. Копия не подлежит изменению. Но обязательно прочитайте документацию по методу перед его использованием, потому что он не работает со списками, содержащими nullценности.

API говорит, что это внутренние коллекции, в вашем случае коллекция не является внутренней

Дело в том, что когда у вас есть закрытый список в классе a гетте для этого списка, вы, возможно, захотите, чтобы вызывающие получатели не могли изменять список в случае, если вам придется возвращать изменяемый список. в противном случае возвращаемый список является просто ссылкой на ваш внутренний / личный список, и, следовательно, его содержимое может быть изменено.

Идея в том, что вы не можете изменить список с помощью a2,

Модификация a1 список действительно изменит то, что вы видите в a2 - это предназначено.

Просто нет публичного способа доступа к списку a1, и вы должны иметь то, что вы хотите:)

Заявление:

Collections.unmodifiableList(a1);

возвращает обертку над исходной коллекцией, чьи методы-модификаторы throw UnsupportedOperationException,

Оболочка для чтения, что означает, что если вы измените a1изменения отражаются на коллекции a2,

a1 а также a2 будет ссылаться на те же данные (память).

неотъемлемая часть приходит, только с a2 как запись

визуализация, если вы проходите a2 к методу, где вы ожидаете, что метод будет идемпотентным. такие случаи a2 помогает.

Таким образом, вы не можете изменить данные, используя a2 указатель.

Если вам нужен неизменяемый и неизменный список или, другими словами, неизменяемая копия исходного списка без какой-либо зависимости от других библиотек, попробуйте это:

Collections.unmodifiableList(Collections.list(Collections.enumeration(sourceList)))

Collections.list() копирует значения из своего перечисления.

Другие вопросы по тегам