Collections.unmodifiableList和防御性副本

时间:2013-02-27 11:35:09

标签: java collections unmodifiable

如果我写

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

a2是只读的,但如果我写

a1.set(0,10);

然后a2也被修改。

如果在API中说:

  

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

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

也许我误解了这个含义,如果是的话,那是什么方式 写一个该集合的防御性副本?

8 个答案:

答案 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)

a1a2将引用相同的数据(内存)。

不可模仿的部分来了,只有a2作为条目。

如果要将a2传递给期望该方法是幂等的方法,请进行

成像。这种情况a2有帮助。

总之,您无法使用a2指针修改数据。

答案 7 :(得分:0)

如果您需要不可修改且不可变的列表,或者换句话说源代码列表的不可修改副本而不依赖于其他库,请尝试:

Collections.unmodifiableList(Collections.list(Collections.enumeration(sourceList)))

Collections.list()从枚举中复制值。