代码之家  ›  专栏  ›  技术社区  ›  Rakesh Juyal

如果我们有原来的列表,为什么我们可以更改不可修改的列表?

  •  6
  • Rakesh Juyal  · 技术社区  · 16 年前

    通过查看 Collections 同学们,我知道当我们使用这个方法的时候 unmodifiableList(List list) unmodifiableCollection(Collection c) 它不是创建新对象,而是返回同一对象的引用并重写可以修改 List [ add addall , remove , retainAll ... ]

    List modifiableList = new ArrayList();
    modifiableList.add ( 1 );   
    List unmodifiableList = Collections.unmodifiableList( modifiableList );
    // unmodifiableList.add(3);  // it will throw the exception 
    modifiableList.add ( 2 );       
    System.out.println( unmodifiableList );
    

    结果是 [ 1,2 ]
    关键是为什么它指的是同一个对象?为什么不创建新对象?

    7 回复  |  直到 16 年前
        1
  •  11
  •   Bozho    16 年前

    (下面是问题的答案)

    你以外的人 -即API的客户端。

    unmodifiableList(..) 创建类型为的新对象 UnmodifiableList (但这不是一个公共类),它获取原始列表,并将所有方法委托给它 除了

    关键是,如文件所述:

    举个例子:你有一个 List 您的API已经检测到并且可以操作的设备的数量,并且您希望为它们提供API的客户机。但他不应该 他们。所以你有两个选择:

    • 给他一份你的简历 列表 你的

    现在来回答你的问题-不可修改的列表是一个 原始收藏。因此,如果您需要向其中添加一个新项目—例如,您发现了一个刚刚插入的新设备,那么客户机将能够在自己的浏览器中看到它 不可修改视图

        2
  •  3
  •   Raoul Duke    16 年前

    现在关键是为什么它是指 同一个物体?为什么不呢 创建新对象?

        3
  •  2
  •   Community Mohan Dere    6 年前

    根据文件:

    public static List unmodifiableList(List list)

    返回不可修改的 看法 指定列表的。此方法允许模块向用户提供 列表。对返回列表的查询操作“读取”到指定的列表,并尝试修改返回的列表(无论是直接修改还是通过其迭代器修改),都会导致UnsupportedOperationException。

        4
  •  1
  •   Community Mohan Dere    9 年前

    The accepted Answer Bozho 是正确的。这里有更多的信息、示例代码和建议的替代方案。

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

    那个 unmodifiableList Collections 实用程序类不创建新列表,而是创建一个伪列表 支持

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

    返回指定列表的不可修改视图。此方法允许模块向用户提供对内部列表的“只读”访问。对返回列表的查询操作“读取”到指定的列表,并尝试修改返回的列表(无论是直接修改还是通过其迭代器修改),都会导致UnsupportedOperationException。

    第四个词是关键: view . 新列表对象不是新列表。它是一个覆盖层。就像 tracing paper transparency film 在图形上方可以阻止您在图形上做标记,但不会阻止您从下方修改原始图形。

    故事的寓意:不要用集合.不可修改列表制作防御性的名单副本。

    同上 Collections.unmodifiableMap , Collections.unmodifiableSet ,等等。

    下面是另一个例子来说明这个问题。

    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]
    

    谷歌番石榴

    而不是 收藏 类,对于防御编程,我建议使用 Google Guava 图书馆及其应用 ImmutableCollections 设施。

    你可以列一个新的清单。

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

    影响(缩小)不变的列表。

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

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

        5
  •  0
  •   Paweł Dyda    16 年前

    我相信秘密在于实施细节。。。集合.不可修改列表()只会给你装饰可修改的列表。我的意思是不可修改列表包含对内部可修改列表的引用。

        6
  •  0
  •   Kumar Abhishek    10 年前

    我发现一个办法就是

    List unmodifiableList = Collections.unmodifiableList( new ArrayList(modifiableList));
    
    List<String> strings = new ArrayList<String>();
            // unmodifiable.add("New string");
            strings.add("Aha 1");
            strings.add("Aha 2");
            List<String> unmodifiable = Collections.unmodifiableList(strings);
            List<String> immutableList = Collections.unmodifiableList(new ArrayList<>(strings));
            // Need some way to fix it so that Strings does not Modify
            strings.add("Aha 3");
            strings.add("Aha 4");
    
            strings.remove(0);
    
            for (String str : unmodifiable) {
                System.out.println("Reference Modified :::" + str);
            }
    
            for (String str : immutableList) {
                System.out.println("Reference Modified :::" + str);
            }
    
        7
  •  -2
  •   Dead Programmer    16 年前
    1. 要创建一个ummodifiable对象,我将包装原始对象,并通过抛出exception防止add、remove。但是你知道,我可以改变列表中的每个对象,比如如果你在一个可修改的列表中有一个person对象,我仍然可以改变列表中person对象的名称。