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
Guava: ImmutableList magic of the copyOf() method
提问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.unmodifiableXXX
methods, 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 temporaryArrayList
(copyOf(Iterable)
andcopyOf(Iterator)
do so).
- (来自源代码)
copyOf(Collection)
实例不会创建临时ArrayList
(copyOf(Iterable)
并且copyOf(Iterator)
这样做)。
回答by Louis Wasserman
ImmutableList
does not magically make the elementsimmutable; it's the list that cannot be modified, not the elements it contains.ImmutableList.copyOf
makes a copy unless it is copying a list that is alreadyanImmutableList
. If you callImmutableList.copyOf(list)
twice for the same immutable list, you will get two different copies.
ImmutableList
不会神奇地使元素不可变;它是无法修改的列表,而不是它包含的元素。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)数据项的引用来更改数据)