java Collections.copy 问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5974407/
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-30 13:47:32  来源:igfitidea点击:

Collections.copy problem

javacollections

提问by javaCollect

I want that b1and b2to have their own sets of elements, then b1 and b2 should have its own elements in memory so that when b1/b2 is modified, others should not be affected.

我想要那个b1并且b2拥有自己的元素集,那么 b1 和 b2 应该在内存中拥有自己的元素,以便在修改 b1/b2 时,其他元素不应该受到影响。

bufferis an ArrayListcontaining many elements

buffer是一个ArrayList包含许多元素

List<Integer>  b1 = new ArrayList<Integer>(buffer.size()) ;
List<Integer>  b2 = new ArrayList<Integer>(buffer.size()) ) ;
Collections.copy(b1, buffer);
Collections.copy(b2, buffer);

I am getting this exception:

我收到此异常:

Exception in thread "main"
java.lang.IndexOutOfBoundsException: Source does not fit in dest
    at java.util.Collections.copy(Collections.java:531)
    at Trees.containsSumPrint(Trees.java:243)
    at Trees.main(Trees.java:125)

回答by ratchet freak

The ArrayList(int)constructor gives a Listthat has size 0 it only ensures that nelements can be added before it needs to reallocate the underlying array.

ArrayList(int)构造提供了一个List具有大小为0,只能确定的n元素可以之前它需要重新分配该底层数组加入。

A better way you can copy the lists is:

复制列表的更好方法是:

b1.addAll(buffer);
b2.addAll(buffer);

The semantics are the same as when you would have first added buffer.size()nulls to each array and called Collections.copy(b1,buffer);

语义与您首先buffer.size()向每个数组添加空值并调用时相同Collections.copy(b1,buffer);



If you want a deep copy (the elements also copied) you are going to have to handle each element separately

如果你想要一个深层副本(元素也被复制),你将不得不分别处理每个元素

for(MyObject obj:buffer){
    b1.add(obj.clone());
    b2.add(obj.clone());
}

回答by Stephen C

The Collections.copy(...)javadocsays this:

Collections.copy(...)javadoc中这样说:

"Copies all of the elements from one list into another. After the operation, the index of each copied element in the destination list will be identical to its index in the source list. The destination list must be at least as long as the source list.If it is longer, the remaining elements in the destination list are unaffected.".

"将一个列表中的所有元素复制到另一个列表中。操作后,目标列表中每个复制元素的索引将与其在源列表中的索引相同。目标列表必须至少与源列表一样长.如果更长,则目标列表中的剩余元素不受影响。” .

The ArrayList(int)constructor creates an empty list whose capacity(not size!) is given by the argument.

ArrayList(int)构造函数创建一个空的列表,它的容量(不大小!)由给定参数。

Since b1is initially empty, copying a non-empty list to it (using copy) will fail, since the precondition (in bold) does not hold true (in general).

由于b1最初为空,将非空列表复制到它(使用copy)将失败,因为前提条件(粗体)不成立(通常)。

Basically, Collections.copy(...)is the wrong method to use.

基本上,Collections.copy(...)是使用错误的方法。

What you should really be doing is this:

你真正应该做的是:

List<Integer> b1 = new ArrayList<Integer>(buffer.size());
List<Integer> b2 = new ArrayList<Integer>(buffer.size());
b1.addAll(buffer);
b2.addAll(buffer);


I'm assuming that you don't reallywant to create new instances of the list elements. If you do, I should point out that creating new instances of Integerobjects is waste of time since Integer(like the other wrapper classes and String) is an immutable class.

我假设您真的不想创建列表元素的新实例。如果你这样做了,我应该指出创建Integer对象的新实例是浪费时间,因为Integer(像其他包装类和String)是一个不可变的类。

回答by Adriaan Koster

You want a deep copy of each element. There is no standard way to achieve this, because deep copying could involve copying nested references to (collections of) other objects. The best way to do this is create a copy constructor, java.lang.Integer happens to have one! So I think you should do something like:

您需要每个元素的深层副本。没有标准方法可以实现这一点,因为深度复制可能涉及复制对其他对象(的集合)的嵌套引用。最好的方法是创建一个复制构造函数,java.lang.Integer 恰好有一个!所以我认为你应该这样做:

List<Integer> buffer = Arrays.asList(new Integer[] { 0, 1, 2, 3, 4 });
List<Integer> b1 = new ArrayList<Integer>();
List<Integer> b2 = new ArrayList<Integer>();

for (Integer element : buffer) {
    b1.add(new Integer(element));
    b2.add(new Integer(element));
}

This actually creates TWO copies, one in each target list. If one of the lists may contain the original elements just do:

这实际上创建了两个副本,每个目标列表中一个。如果其中一个列表可能包含原始元素,请执行以下操作:

for (Integer element : buffer) {
    b1.add(new Integer(element));
    b2.add(element);
}

Note that there also exists the cloneable interface. I advise against using this because it is easy to make mistakes with referred classes, collections and subclassing. A copy constructor is much easier to get right. See this pagefor some corroboration.

请注意,还存在可克隆接口。我建议不要使用它,因为引用类、集合和子类很容易出错。复制构造函数更容易正确。请参阅此页面以获取一些佐证。

EDIT: on re-reading, maybe you don't want deep copies, in which case you can use the 'addAll' method as described by others. This will allow you to create multiple collections of the same object instances. You can then modify the contents/order of objects in one collection without affecting other collections. However if you modify an object instance, this will obviously be reflected by all other collections as well.

编辑:在重新阅读时,也许您不想要深拷贝,在这种情况下,您可以使用其他人描述的“addAll”方法。这将允许您创建相同对象实例的多个集合。然后,您可以修改一个集合中对象的内容/顺序,而不会影响其他集合。但是,如果您修改了一个对象实例,这显然也会反映在所有其他集合中。

Also, StephenC rightfully points out that my above example is nutty. I agree, one would never 'deep copy' Integers like that normally, but it would makes sense for custom objects containing collections/references which I thought was the issue here.

此外,StephenC 正确地指出我上面的例子很疯狂。我同意,人们永远不会像通常那样“深拷贝”整数,但对于包含集合/引用的自定义对象来说,这是有意义的,我认为这是这里的问题。