不可修改的可修改对象列表

时间:2014-08-11 17:05:27

标签: java list unmodifiable

假设我们有一个List<List<String>>,并希望将其完全无法修改。简单地将其传递给Collection.unmodifiableList是不够的,因为内部列表仍然可以被修改。

我会采用以下方法:

List<List<String>> someList;

让它无法修改:

List<List<String>> tempList = new ArrayList<>();
for(List<String> strList : someList) {
    tempList.add(Collections.unmodifiableList(strList));
}
List<List<String>> safeList = Collections.unmodifiableList(tempList);

这种方法可以吗?

4 个答案:

答案 0 :(得分:1)

只要您不保留对原始可修改列表的引用,此方法就可以正常工作。此类引用可以修改由不可修改列表包含的列表。

答案 1 :(得分:1)

实现不变性的方法是创建防御性副本。

中的数据

每当将可变对象传递给您的方法时,您都会创建它的深层副本。如果你想要最大的安全性,这应该是你做的第一件事,甚至在你检查有效性之前。

将列表包装到Collections.unmodifiableList()这里不起作用,因为无法保证基础列表不会被第三方修改。换句话说,你无法控制实例。

创建列表的不可变副本的好方法是使用Google Guava的ImmutableList.copyOf()方法,但请记住,您需要一个深层副本,因此您需要在主列表中创建列表的不可变副本。

数据输出

每当您返回一个值时,您都会制作另一个防御性副本,以便对返回的对象的更改不会反映出来。在这里,您可以在列表中使用不可修改的包装器(例如ImmutableList.of()),因为您只保留对原始列表的引用。

如果您同时执行这两项操作(在途中复制,复制/包装出路),您的代码将是安全和正确的。可以给出任何其他解决方案并且没有这样的一般保证,您的代码可能或许多不正确。

答案 2 :(得分:1)

我觉得它不起作用: -

    List<List<String>> someList = new ArrayList<>();

            List<String> l1 = new ArrayList<String>();
            List<String> l2 = new ArrayList<String>();

            l1.add("STR1");
            l1.add("STR2");
            l1.add("STR3");

            l2.add("STR4");
            l2.add("STR5");
            l2.add("STR6");

            someList.add(l1);
            someList.add(l2);

            List<List<String>> tempList = new ArrayList<>();
            for(List<String> strList : someList) {
                tempList.add(Collections.unmodifiableList(strList));
            }
            List<List<String>> safeList = Collections.unmodifiableList(tempList);

            l1.add("STR7"); // The inner list reference is modified which causes the 
safelist internal structure to get changed

            for(List<String> safeInnerList : safeList) {
                System.out.println(safeInnerList);

            }

答案 3 :(得分:1)

以下代码应该: -

            List<List<String>> tempList = new ArrayList<>();
            for(List<String> strList : someList) {
                tempList.add(new ArrayList<>(strList));
            }
            List<List<String>> safeList = Collections.unmodifiableList(tempList);

这是对此的测试: -

List<List<String>> someList = new ArrayList<>();

        List<String> l1 = new ArrayList<String>();
        List<String> l2 = new ArrayList<String>();

        l1.add("STR1");
        l1.add("STR2");
        l1.add("STR3");

        l2.add("STR4");
        l2.add("STR5");
        l2.add("STR6");

        someList.add(l1);
        someList.add(l2);

        List<List<String>> tempList = new ArrayList<>();
        for(List<String> strList : someList) {
            tempList.add(new ArrayList<>(strList));
        }
        List<List<String>> safeList = Collections.unmodifiableList(tempList);

        l1.add("STR7"); // The inner list reference is modified this doesnot cause the safelist internal structure to get changed

        for(List<String> safeInnerList : safeList) {
            System.out.println(safeInnerList);
        }