Collections.unmodifiableList 和 defensive copy

2022-08-31 20:59:03

如果我写

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

a2是只读的,但如果我写

a1.set(0,10);

然后也被修改。a2

如果在 API 中说:

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

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

也许我是否误解了其中的含义,如果是这样,那么写一个防御性的副本是什么?


答案 1

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

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

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

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

由于没有任何东西可以引用所创建的,这是一个真正不可修改的集合。ListasList

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

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


答案 2

也许我是否误解了其中的含义,如果是这样,那么写一个防御性的副本是什么?

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

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

public List<Integer> getUnmodifiable() {
    return Collections.unmodifiableList(a1);
}

调用无权访问类内部(即他们无法访问私有变量)的人将无法修改返回的列表。getUnmodifiablea1