关于不可修改的收集

时间:2014-03-17 11:41:14

标签: java collections

请考虑以下代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Test {

    public static void main(String[] args) {
        List<Integer> intList1=new ArrayList<Integer>();
        List<Integer> intList2;
        intList1.add(1);
        intList1.add(2);
        intList1.add(3);
        intList2=Collections.unmodifiableList(intList1);
        intList1.add(4);

        for(int i=0;i<4;i++)
        {
            System.out.println(intList2.get(i));
        }
    }

}

上述代码的结果是

1
2
3
4

在上面的代码中,我们从List intList2 1的内容创建了一个不可修改的 List intList。但在Collections.unmodifiable声明后,当我对intList1进行更改时,该更改会反映为intList2。这怎么可能?

5 个答案:

答案 0 :(得分:3)

您需要阅读Javadoc for Collections.unmodifiableList

  

返回指定列表的不可修改视图。

这意味着返回的视图是不可修改的。如果您有原始参考,则可以更改集合。如果更改了集合,则更改将反映在视图中。

这样做的好处是速度非常快,即您不需要复制集合,但是您注意到的缺点 - 生成的集合是一个视图。

为了创建真正不可修改的集合,您需要复制然后换行:

intList2=Collections.unmodifiableList(new ArrayList<>(intList1));

这会将intList1的内容复制到另一个集合中,然后将该集合包装在不可修改的变量中。不存在对包装集合的引用。

这是昂贵的 - 整个底层数据存储区(在这种情况下是一个数组)需要重复,通常需要O(n)

Google Guava提供immutable collections解决了制作防御性副本的一些问题:

  • 如果集合已经是不可变的,则不会再次复制
  • 提供一个可用于明确声明集合是不可变的接口
  • 提供许多静态工厂方法来生成不可变集合

但是,当使用集合的不可变副本而不是不可修改的视图时,速度仍然是关键问题。

应该注意Collections.unmodifiableXXX的通常用法是从方法返回,例如getter:

public Collection<Thing> getThings() {
    return Collections.unmodifiableCollection(things);
}

在这种情况下,有两点需要注意:

  1. getThings的用户无法访问things,因此无法修改无法修改。
  2. 每次调用getter时复制things都会非常昂贵。
  3. 总之,您的问题的答案比您预期的要复杂得多,在您的应用程序中传递集合时需要考虑许多方面。

答案 1 :(得分:1)

来自Collections.unmodifiableList的Javadoc:

  

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

它阻止修改返回的列表,但原始列表本身仍然可以。

答案 2 :(得分:1)

Collections.unmodifiableList返回内部列表的“只读”视图。虽然返回的对象不可修改,但可以修改它引用的原始列表。两个对象都指向内存中的同一个对象,因此它将反映所做的更改。

Here是对正在发生的事情的一个很好的解释。

答案 3 :(得分:0)

发生这种情况是因为不可修改的列表在内部支持第一个列表,如果您真的希望它不可修改,则不应再使用第一个列表。

答案 4 :(得分:0)

在您的代码中

 intList2=Collections.unmodifiableList(intList1);

在intList2中创建unmodifiableList。因此您可以自由地在inList1中进行更改 但是你不允许在intList2中做任何改变

试试这个:      intList2.add(4); 你会得到

 java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.add(Unknown Source)

以上异常。