Collections.unmodifiableList和防御性副本

xde*_*000 41 java collections unmodifiable

如果我写

List<Integer> a1 = Arrays.asList(1, 2, 3);
List<Integer> a2 = Collections.unmodifiableList(a1);
Run Code Online (Sandbox Code Playgroud)

a2 是只读的,但如果我写

a1.set(0,10);
Run Code Online (Sandbox Code Playgroud)

然后a2也被修改了.

如果在API中说:

返回指定集合的​​不可修改视图.此方法允许模块为用户提供对内部集合的"只读"访问.

那么,为什么我修改原始集合也修改了目标复制集合?

也许我误解了它的意思,如果是这样,那么写一个防御性的副本是什么方式?

Joa*_*uer 49

是的,你理解正确.这个想法是返回的对象umodifiableCollection不能直接改变,但可以通过其他方式改变(有效地通过直接更改内部集合).

只要有东西可以访问内部列表,就可以更改"不可修改"的集合.

这就是为什么你通常构建一个不可修改的集合,并确保没有任何东西可以进入内部列表:

Collection<Integer> myUmodifiableCollection = Collection.umodifiableCollection(Arrays.asList(1, 2, 3));
Run Code Online (Sandbox Code Playgroud)

由于没有任何东西可以获得对List创建者的引用asList,因此这是一个真正无法修改的集合.

这种方法的优点是您根本不需要复制原始集合/列表,这避免了使用内存和计算能力.

Guava提供了ImmutableCollection类(及其子类,例如ImmutableList),它提供了真正的不可变集合(通常通过复制源代码).

  • @Geek:当`Arras.asList()`返回一个固定大小的List时,它不会返回一个不可修改的List.你仍然可以使用`set(int,T)`来改变元素.`Collections.unmodifiableList()通过禁止它来"修复"它.但在任何现实世界的代码中,我可能只使用Guava`ImputableList`(链接到上面),因为它写得比较短,非常清楚,并且始终确保没有任何东西可以"泄漏". (7认同)

ass*_*ias 10

也许我误解了它的意思,如果是这样,那么写一个防御性的副本是什么方式?

通常,您会以这种方式使用它:

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

public List<Integer> getUnmodifiable() {
    return Collections.unmodifiableList(a1);
}
Run Code Online (Sandbox Code Playgroud)

调用getUnmodifiable 并且无法访问类内部的人(即他们无法访问私有变量a1)将无法修改返回的列表.

  • 您无法添加到a1,但可以将任何项目设置为不同的项目. (3认同)