Рассмотрим следующий ниже код
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Integer> intList1=new ArrayList<Integer>();
List<Integer> intList2;
intList1.add(1);
intList1.add(2);
intList1.add(3);
intList2=Collections.unmodifiableList(intList1);
intList1.add(4);
for(int i=0;i<4;i++)
{
System.out.println(intList2.get(i));
}
}
}
Результатом приведенного выше кода является
1
2
3
4
В приведенном выше коде мы создаем неизменяемый List intList2
из содержимого List intList
1. Но после Collections.unmodifiable
заявления, когда я внести изменения в intList1
, что изменение отражает в intList2
. Как это возможно?
Вам необходимо прочитать Javadoc для Collections.unmodifiableList
Возвращает немодифицируемое представление указанного списка.
Это означает, что возвращаемое представление не поддается изменению. Если у вас есть исходная ссылка, вы можете изменить коллекцию. Если вы измените коллекцию, изменения будут отражены в представлении.
Это имеет то преимущество, что очень быстро, т.е. Вам не нужно копировать коллекцию, но недостаток, который вы отметили, - итоговая коллекция - это представление.
Чтобы создать действительно немодифицируемую коллекцию, вам нужно будет скопировать и обернуть:
intList2=Collections.unmodifiableList(new ArrayList<>(intList1));
Это копирует содержимое intList1
в другую коллекцию, а затем обертывает эту коллекцию в неизменяемой переменной. Нет ссылки на обернутую коллекцию.
Это дорого - весь базовый хранилище данных (массив в этом случае) необходимо дублировать, который (как правило) принимает O(n)
.
Google Guava предоставляет непреложные коллекции, которые решают некоторые проблемы создания защитных копий:
Но скорость все еще остается главной проблемой при использовании неизменяемых копий коллекций, а не неизменяемых представлений.
Следует отметить, что обычное использование Collections.unmodifiableXXX
- это возврат из метода, например, getter:
public Collection<Thing> getThings() {
return Collections.unmodifiableCollection(things);
}
В этом случае можно отметить две вещи:
getThings
не может получить доступ к things
поэтому getThings
не может быть нарушена.things
каждый раз, когда вызывал геттер.Таким образом, ответ на ваш вопрос немного сложнее, чем вы могли ожидать, и при рассмотрении коллекций в вашем приложении необходимо учитывать ряд аспектов.
Collections.unmodifiableList возвращает вид "только для чтения" внутреннего списка. Хотя возвращаемый объект не модифицируется, исходный список, который он ссылается, может быть изменен. Оба объекта указывают на один и тот же объект в памяти, чтобы он отражал сделанные изменения.
Вот хорошее объяснение того, что происходит.
Из Javadoc of Collections.unmodifiableList:
Возвращает немодифицируемое представление указанного списка. Этот метод позволяет модулям предоставлять пользователям доступ к внутренним спискам "только для чтения".
Это предотвращает изменение возвращаемого списка, но сам исходный список по-прежнему может быть.
Это происходит потому, что немодифицируемый список внутренне поддерживается для первого списка, если вы действительно хотите, чтобы он был немодифицируемым, вы больше не должны использовать первый список.
В вашем коде вы
intList2=Collections.unmodifiableList(intList1);
создание unmodifiableList в intList2. Таким образом, вы можете вносить изменения в inList1, но вам не разрешено делать какие-либо изменения в intList2
попробуйте это: intList2.add(4); ты получишь
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.add(Unknown Source)
выше исключения.