如果我写
List<Integer> a1 = Arrays.asList(1, 2, 3);
List<Integer> a2 = Collections.unmodifiableList(a1);
a2
是只读的,但如果我写
a1.set(0,10);
然后a2
也被修改。
如果在API中说:
返回指定集合的不可修改视图。这种方法 允许模块为用户提供对内部的“只读”访问 集合。
那么,为什么我修改原始集合也会修改目标复制的集合?
也许我误解了这个含义,如果是的话,那是什么方式 写一个该集合的防御性副本?
答案 0 :(得分:48)
是的,你理解正确。我们的想法是umodifiableCollection
返回的对象无法直接更改,但可以通过其他方式进行更改(通过直接更改内部集合来实现)。
只要有东西可以访问内部列表,就可以更改“不可修改”的集合。
这就是为什么你通常构建一个不可修改的集合,并确保没有任何东西可以进入内部列表:
Collection<Integer> myUmodifiableCollection = Collection.umodifiableCollection(Arrays.asList(1, 2, 3));
由于没有任何内容可以引用List
创建的asList
,因此这是一个真正无法修改的集合。
这种方法的优点是您根本不需要复制原始集合/列表,这样可以避免使用内存和计算能力。
Guava提供ImmutableCollection
类(及其子类,如ImmutableList
),它们提供真正的不可变集合(通常通过复制源代码)。
答案 1 :(得分:10)
也许我误解了这个含义,如果是这样的话,那么写一个该集合的防御性副本的方式是什么?
通常情况下,你会这样使用它:
private List<Integer> a1 = Arrays.asList(1, 2, 3);
public List<Integer> getUnmodifiable() {
return Collections.unmodifiableList(a1);
}
调用getUnmodifiable
和的人无权访问您的类的内部(即他们无法访问私有变量a1
),将不会能够修改返回的列表。
答案 2 :(得分:1)
我们的想法是您无法通过a2
修改列表。
修改a1
列表确实会修改您在a2
中看到的内容 - 这是预期的。
只是没有公开的方式来访问列表a1
,你应该拥有你想要的东西:)
答案 3 :(得分:1)
API表示内部集合,在您的情况下,集合不是内部
关键是当你在课堂上有一个私人列表和该列表的gettet时,你可能希望getter的调用者无法修改列表,因为你必须返回一个umodifiable列表。否则返回的列表只是对您的内部/私人列表的引用,因此可以修改其内容。
答案 4 :(得分:1)
声明:
Collections.unmodifiableList(a1);
在原始集合上返回一个包装器,其修饰符方法抛出UnsupportedOperationException
。
包装器是直读的,这意味着如果您修改a1
,则更改会反映在包装集合a2
上。
答案 5 :(得分:1)
如果您希望保持a1
可变并在没有番石榴的情况下对其进行不可变的复制,则这是您可以做到的一种方法。
List<Integer> a1 = Arrays.asList(1, 2, 3);
List<Integer> a2 = Collections.unmodifiableList(new ArrayList<>(a1));
答案 6 :(得分:0)
a1
和a2
将引用相同的数据(内存)。
不可模仿的部分来了,只有a2
作为条目。
a2
传递给期望该方法是幂等的方法,请进行成像。这种情况a2
有帮助。
总之,您无法使用a2
指针修改数据。
答案 7 :(得分:0)
如果您需要不可修改且不可变的列表,或者换句话说源代码列表的不可修改副本而不依赖于其他库,请尝试:
Collections.unmodifiableList(Collections.list(Collections.enumeration(sourceList)))
Collections.list()
从枚举中复制值。