假设我们有一个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);
这种方法可以吗?
答案 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);
}