java Guava:copyOf() 方法的 ImmutableList 魔法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16765240/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 23:56:49  来源:igfitidea点击:

Guava: ImmutableList magic of the copyOf() method

javacollectionsguava

提问by ses

I would like to feel the 'magic power' of the copyOf()method of Guava guava-libraries.

很想感受一下copyOf()番石榴之法的‘魔力’ guava-libraries

There is small app that I use to check it.

我用一个小应用程序来检查它。

Here is the documentation:

这是文档

The JDK provides Collections.unmodifiableXXXmethods, but in our opinion, these can be

  • unwieldy and verbose; unpleasant to use everywhere you want to make defensive copies
  • unsafe: the returned collections are only truly immutable if nobody holds a reference to the original collection

JDK 提供了Collections.unmodifiableXXX方法,但在我们看来,这些可以是

  • 笨拙而冗长;不愉快在任何你想制作防御性副本的地方使用
  • 不安全:只有在没有人持有对原始集合的引用时,返回的集合才是真正不可变的

So, I try to build a model where "someone holds a reference to the original collection". Thus, working with a copy of collection I should not be worried about changing value on copy. But magic does not work so far (there are two tries: 1. copyOf(collection), 2. copyOf(iterator)):

因此,我尝试构建一个模型,其中"someone holds a reference to the original collection". 因此,使用收藏的副本我不应该担心更改副本的价值。但是到目前为止,魔术还不起作用(有两次尝试: 1. copyOf(collection)、 2. copyOf(iterator)):

import com.google.common.collect.ImmutableList;

import java.util.LinkedList;
import java.util.List;

class MyObject {    
    String name;    
    public MyObject(String name) {this.name = name;}    
    @Override
    public String toString() {
      return name;
    }    
}

public class ListUnsafe {

    List<MyObject> list = new LinkedList<MyObject>();    
    {
        list.add(new MyObject("a"));
        list.add(new MyObject("b"));
        list.add(new MyObject("c"));
    }

    public List<MyObject> getList() {
        return ImmutableList.copyOf(list);
    }

    public List<MyObject> getCopyIterator() {
        return ImmutableList.copyOf(list.iterator());
    }

    public static void main(String[] args) {

        ListUnsafe obj = new ListUnsafe();
        {
           MyObject ref = obj.list.get(0);

           List<MyObject> myList =  obj.getList();

           MyObject copyObj = myList.get(0);
           copyObj.name = "new";

           System.out.println("ref: " + ref);
        }

        obj = new ListUnsafe();
        {
            MyObject ref = obj.list.get(0);

            List<MyObject> myList =  obj.getCopyIterator();

            MyObject copyObj = myList.iterator().next();

            copyObj.name = "new";

            System.out.println("ref: " + ref);

        }

    }

}

The output:

输出:

ref: new
ref: new

It means that we changed original data. What we did not want.

这意味着我们更改了原始数据。我们不想要的。

Question

问题

Why it does not do copy?
How it differs from unmodifiableXXX?

为什么它不做复制?
它与unmodifiableXXX? 有何不同?

There is linkto similar question:

有类似问题的链接

The answer says about copyOf:

答案是关于copyOf

  • (from source) copyOf(Collection)instance doesn't create temporary ArrayList(copyOf(Iterable)and copyOf(Iterator)do so).
  • (来自源代码)copyOf(Collection)实例不会创建临时ArrayListcopyOf(Iterable)并且copyOf(Iterator)这样做)。

回答by Louis Wasserman

  1. ImmutableListdoes not magically make the elementsimmutable; it's the list that cannot be modified, not the elements it contains.
  2. ImmutableList.copyOfmakes a copy unless it is copying a list that is alreadyan ImmutableList. If you call ImmutableList.copyOf(list)twice for the same immutable list, you will get two different copies.
  1. ImmutableList不会神奇地使元素不可变;它是无法修改的列表,而不是它包含的元素。
  2. ImmutableList.copyOf制作一个副本,除非它正在复制一个已经ImmutableList. 如果您ImmutableList.copyOf(list)为同一个不可变列表调用两次,您将获得两个不同的副本。

回答by ses

First of all thank you for all answers. I came up win an example that satisfies me. That shows difference between ImmutableSet.copyOf(..)and JDK's Collections.unmodifiableSet(..);

首先感谢大家的回答。我想出了一个让我满意的例子。这显示了ImmutableSet.copyOf(..)和 JDK之间的区别Collections.unmodifiableSet(..);

And yes: it does shallow copy(otherwise it was strange, because it was magic).

是的:它does shallow copy(否则很奇怪,因为它很神奇)。

class Person {
    public Person(String name) {this.name = name;}
    public Person(String name, Person relation) {this(name);this.relation = relation;}

    String name;
    Person relation;
}

public class ImmutableExample {
    public static void main(String[] args) {

        Person bob = new Person("bob");
        Person chris = new Person("chris", bob);
        Person nullPerson = null; // NULL!

        final Set<Person> originalSet = new LinkedHashSet<Person>(Arrays.asList(
                bob,
                chris
                // nullPerson // NULL !  <- if we use null then we can not convert it to ImmutableSet
               ));

        Set<Person> googleSet = ImmutableSet.copyOf(originalSet);

        Set<Person> javaSet = Collections.unmodifiableSet(originalSet);

        // is it SAFE to delete someone from original collection?
        originalSet.remove(chris);

        // google
        for (Person person : googleSet) System.out.println(person.name); // Chris is still here! And this is good! Stay with us, Chris!

        // java standard
        for (Person person : javaSet) System.out.println(person.name); // Where is Chris ??

        //newSet.add(new Person("newGuy"));  // UnsupportedOperationException

    }
}

(The purpose of original question, though was providing client absolutely safe list for reading. But this could be achieved only with manual cloning of all objects in the list [if they are not immutable]. To provide something that even better (in terms of immutability and concurrency safety) than CopyOnWriteArrayList. I mean: it provides safe iterator, but not data itself if they are mutable in the returning list - client still can change data using references to returned (by getter) data items)

(原始问题的目的是为客户提供绝对安全的阅读列表。但这只能通过手动克隆列表中的所有对象来实现[如果它们不是不可变的]。提供更好的东西(就不变性和并发安全性)比CopyOnWriteArrayList。我的意思是:它提供安全iterator,但不提供数据本身,如果它们在返回列表中是可变的 - 客户端仍然可以使用对返回(通过 getter)数据项的引用来更改数据)