java – 为什么我的`unmodifiableList`可以修改?

前端之家收集整理的这篇文章主要介绍了java – 为什么我的`unmodifiableList`可以修改?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
参见英文答案 > Why can we change the unmodifiable list if we have the original one?7个
我想要一个List,其元素不能被删除也不能添加.我以为我在Java 8中找到了 Collections.unmodifiableList的答案.我通过了我的原始列表并找回了一个据称无法修改的列表.

然而,当我从原始列表中删除元素时,我的不可修改列表被修改.到底是怎么回事?

请参阅此演示代码.从原始文件删除时,我的不可修改列表从3个元素2缩小.

String dog = "dog";
String cat = "cat";
String bird = "bird";

List< String > originalList = new ArrayList<>( 3 );
originalList.add( dog );
originalList.add( cat );
originalList.add( bird );

List< String > unmodList = Collections.unmodifiableList( originalList );
System.out.println( "unmod before: " + unmodList );  // Yields [dog,cat,bird]
originalList.remove( cat );  // Removing element from original list affects the unmodifiable list?
System.out.println( "unmod after: " + unmodList );  // Yields [dog,bird]

解决方法

不可修改的列表由原始列表支持

Collections实用程序类中的unmodifiableList方法不会创建新列表,它会创建由原始列表支持的伪列表.通过“不可修改”对象进行的任何添加删除尝试都将被阻止,因此名称符合其目的.但实际上,如您所示,原始列表可以被修改,同时影响我们的次要非完全不可修改的列表.

这在课程文档中有详细说明:

Returns an unmodifiable view of the specified list. This method allows modules to provide users with “read-only” access to internal lists. Query operations on the returned list “read through” to the specified list,and attempts to modify the returned list,whether direct or via its iterator,result in an UnsupportedOperationException.

第四个词是关键:观点.新列表对象不是新列表.这是一个叠加.就像图纸上的tracing papertransparency film阻止您在图纸上制作标记一样,它不会阻止您在下面修改原始图纸.

故事的道德:不要使用Collections.unmodifiableList来制作列表的防御性副本.

同上Collections.unmodifiableMap,Collections.unmodifiableSet,依此类推.

谷歌番石榴

对于防御性编程而不是Collections类,我建议使用Google Guava库及其ImmutableCollections工具.

你可以列一个新的清单.

public static final ImmutableList<String> ANIMALS = ImmutableList.of(
        dog,bird );

或者您可以制作现有列表的防御性副本.在这种情况下,您将获得一个新的单独列表.从原始列表中删除不会影响(缩小)不可变列表.

ImmutableList<String> ANIMALS = ImmutableList.copyOf( originalList ); // defensive copy!

但请记住,虽然集合自己的定义是独立的,但是包含的对象由原始列表和新的不可变列表共享.在制作防御性副本时,我们不会复制“狗”对象.只有一个狗对象保留在内存中,两个列表都包含指向同一只狗的引用.如果修改了“dog”对象中的属性,则两个集合都指向同一个单个dog对象,因此两个集合都将看到dog的新属性值.

猜你在找的Java相关文章