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