Collections.unmodifiableList和防御性副本


问题内容

如果我写

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

a2 是只读的,但是如果我写

a1.set(0,10);

然后a2也被修改。

如果在API中表示:

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

那么,为什么如果我修改原始集合又修改了目标复制的集合?

也许我误解了含义,如果是的话,写一份防御性副本的方式是什么?


问题答案:

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

只要可以访问内部列表,就可以更改“不可修改的”集合。

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

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

由于没有人引用过List创建者by asList,因此这是一个真正不可修改的集合。

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

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