如何复制 Java 集合列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/689370/
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
How to copy Java Collections list
提问by Jasper Floor
I have an ArrayList
and I want to copy it exactly. I use utility classes when possible on the assumption that someone spent some time making it correct. So naturally, I end up with the Collections
class which contains a copy method.
我有一个ArrayList
,我想完全复制它。我尽可能使用实用程序类,假设有人花了一些时间使其正确。所以很自然地,我最终得到了Collections
包含复制方法的类。
Suppose I have the following:
假设我有以下内容:
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b,a);
This fails because basically it thinks b
isn't big enough to hold a
. Yes I know b
has size 0, but it should be big enough now shouldn't it? If I have to fill b
first, then Collections.copy()
becomes a completely useless function in my mind. So, except for programming a copy function (which I'm going to do now) is there a proper way to do this?
这失败了,因为基本上它认为b
不足以容纳a
. 是的,我知道b
尺寸为 0,但现在应该足够大了,不是吗?如果非b
要先填,那Collections.copy()
在我脑子里就变成完全没用的功能了。那么,除了编写复制功能(我现在要做的)之外,是否有合适的方法来做到这一点?
采纳答案by Stephen Katulka
Calling
打电话
List<String> b = new ArrayList<String>(a);
creates a shallow copy of a
within b
. All elements will exist within b
in the exact same order that they were within a
(assuming it had an order).
创建的浅表副本a
内b
。所有元素都将以它们b
所在的完全相同的顺序存在于其中a
(假设它有一个顺序)。
Similarly, calling
同样,调用
// note: instantiating with a.size() gives `b` enough capacity to hold everything
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b, a);
also creates a shallow copy of a
within b
. If the first parameter, b
, does not have enough capacity(not size) to contain all of a
's elements, then it will throw an IndexOutOfBoundsException
. The expectation is that no allocations will be required by Collections.copy
to work, and if any are, then it throws that exception. It's an optimization to require the copied collection to be preallocated (b
), but I generally do not think that the feature is worth it due to the required checks given the constructor-based alternatives like the one shown above that have no weird side effects.
还创建的浅表副本a
内b
。如果第一个参数 ,b
没有足够的容量(不是大小)来包含 的所有a
元素,那么它将抛出一个IndexOutOfBoundsException
. 期望是不需要分配Collections.copy
来工作,如果有,则抛出该异常。要求预先分配复制的集合是一种优化 ( b
),但我通常认为该功能不值得,因为鉴于基于构造函数的替代方案(例如上面显示的替代方案没有奇怪的副作用),需要进行必要的检查。
To create a deep copy, the List
, via either mechanism, would have to have intricate knowledge of the underlying type. In the case of String
s, which are immutable in Java (and .NET for that matter), you don't even need a deep copy. In the case of MySpecialObject
, you need to know how to make a deep copy of it and that is not a generic operation.
要创建深层副本,List
通过任何一种机制, 都必须具有底层类型的复杂知识。在String
s的情况下,它在 Java(和 .NET 中)是不可变的,你甚至不需要深拷贝。在 的情况下MySpecialObject
,您需要知道如何制作它的深层副本,这不是通用操作。
Note: The originally accepted answer was the top result for Collections.copy
in Google, and it was flat out wrong as pointed out in the comments.
注意:最初接受的答案是Collections.copy
谷歌的最高结果,正如评论中指出的那样,这是完全错误的。
回答by tddmonkey
Just do:
做就是了:
List a = new ArrayList();
a.add("a");
a.add("b");
a.add("c");
List b = new ArrayList(a);
ArrayList has a constructor that will accept another Collection to copy the elements from
ArrayList 有一个构造函数,它将接受另一个 Collection 来复制元素
回答by Jon Skeet
b
has a capacityof 3, but a sizeof 0. The fact that ArrayList
has some sort of buffer capacity is an implementation detail - it's not part of the List
interface, so Collections.copy(List, List)
doesn't use it. It would be ugly for it to special-case ArrayList
.
b
有一个容量为3,但是大小为0的事实ArrayList
具有某种缓冲能力是一个实现细节-它不是一部分List
的接口,所以Collections.copy(List, List)
不使用它。特殊情况下它会很难看ArrayList
。
As MrWiggles has indicated, using the ArrayList constructor which takes a collection is the way to in the example provided.
正如 MrWiggles 所指出的,在提供的示例中,使用接受集合的 ArrayList 构造函数是一种方法。
For more complicated scenarios (which may well include your real code), you may find the collections within Guavauseful.
对于更复杂的场景(很可能包括您的真实代码),您可能会发现Guava 中的集合很有用。
回答by Gareth Davis
the simplest way to copy a List is to pass it to the constructor of the new list:
复制 List 的最简单方法是将其传递给新列表的构造函数:
List<String> b = new ArrayList<>(a);
b
will be a shallow copy of a
b
将是一个浅拷贝 a
Looking at the source of Collections.copy(List,List)
(I'd never seen it before) it seems to be for coping the elements index by index. using List.set(int,E)
thus element 0 will over write element 0 in the target list etc etc. Not particularly clear from the javadocs I'd have to admit.
查看Collections.copy(List,List)
(我以前从未见过)的来源,它似乎是用于按索引处理元素索引。List.set(int,E)
因此,使用元素 0 将覆盖目标列表中的元素 0 等。从我不得不承认的 javadocs 中不是特别清楚。
List<String> a = new ArrayList<>(a);
a.add("foo");
b.add("bar");
List<String> b = new ArrayList<>(a); // shallow copy 'a'
// the following will all hold
assert a.get(0) == b.get(0);
assert a.get(1) == b.get(1);
assert a.equals(b);
assert a != b; // 'a' is not the same object as 'b'
回答by Martin C.
If you want to copy an ArrayList, copy it by using:
如果要复制 ArrayList,请使用以下命令复制它:
List b = new ArrayList();
b.add("aa");
b.add("bb");
List a = new ArrayList(b);
回答by cletus
List b = new ArrayList(a.size())
doesn't set the size. It sets the initial capacity (being how many elements it can fit in before it needs to resize). A simpler way of copying in this case is:
不设置大小。它设置初始容量(即在需要调整大小之前可以容纳多少元素)。在这种情况下,一种更简单的复制方法是:
List b = new ArrayList(a);
回答by ordnungswidrig
Copy isn't useless if you imagine the use case to copy some values into an existing collection. I.e. you want to overwrite existing elements instead of inserting.
如果您想象将某些值复制到现有集合中的用例,则复制并非无用。即您想覆盖现有元素而不是插入。
An example: a = [1,2,3,4,5] b = [2,2,2,2,3,3,3,3,3,4,4,4,] a.copy(b) = [1,2,3,4,5,3,3,3,3,4,4,4]
一个例子:a = [1,2,3,4,5] b = [2,2,2,2,3,3,3,3,3,4,4,4,] a.copy(b) = [1,2,3,4,5,3,3,3,3,4,4,4]
However I'd expect a copy method that would take additional parameters for the start index of the source and target collection, as well as a parameter for count.
但是,我希望有一个复制方法,该方法将为源和目标集合的起始索引以及计数参数采用其他参数。
See Java BUG 6350752
参见 Java BUG 6350752
回答by hoijui
The answer by Stephen Katulka (accepted answer) is wrong (the second part).
It explains that Collections.copy(b, a);
does a deep copy, which it does not. Both, new ArrayList(a);
and Collections.copy(b, a);
only do a shallow copy. The difference is, that the constructor allocates new memory, and copy(...)
does not, which makes it suitable in cases where you can reuse arrays, as it has a performance advantage there.
Stephen Katulka 的答案(已接受的答案)是错误的(第二部分)。它解释说Collections.copy(b, a);
会进行深度复制,而不会。这两种,new ArrayList(a);
而Collections.copy(b, a);
只能做一个浅拷贝。不同之处在于,构造函数分配新内存,而copy(...)
不会分配,这使其适用于可以重用数组的情况,因为它在那里具有性能优势。
The Java standard API tries to discourage the use of deep copies, as it would be bad if new coders would use this on a regular basis, which may also be one of the reason why clone()
is not public by default.
Java 标准 API 试图阻止使用深度副本,因为如果新编码人员定期使用它会很糟糕,这也可能clone()
是默认情况下不公开的原因之一。
The source code for Collections.copy(...)
can be seen on line 552 at:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/Collections.java.htm
的源代码Collections.copy(...)
可以在第 552 行看到:http:
//www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/集合.java.htm
If you need a deep copy, you have to iterate over the items manually, using a for loop and clone() on each object.
如果您需要深拷贝,您必须手动迭代这些项目,在每个对象上使用 for 循环和 clone()。
回答by felix
Strings can be deep copied with
字符串可以被深度复制
List<String> b = new ArrayList<String>(a);
because they are immutable. Every other Object not --> you need to iterate and do a copy by yourself.
因为它们是不可变的。不是每个其他对象 --> 您需要迭代并自己复制。
回答by Michael Welch
As hoijui mentions. The selected answer from Stephen Katulka contains a comment about Collections.copy that is incorrect. The author probably accepted it because the first line of code was doing the copy that he wanted. The additional call to Collections.copy just copies again. (Resulting in the copy happening twice).
正如海瑞所说。来自 Stephen Katulka 的选定答案包含关于 Collections.copy 的不正确评论。作者可能接受了它,因为第一行代码正在做他想要的副本。对 Collections.copy 的额外调用只是再次复制。(导致复制发生两次)。
Here is code to prove it.
这是证明它的代码。
public static void main(String[] args) {
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a);
System.out.println("There should be no output after this line.");
// Note, b is already a shallow copy of a;
for (int i = 0; i < a.size(); i++) {
if (a.get(i) != b.get(i)) {
System.out.println("Oops, this was a deep copy."); // Note this is never called.
}
}
// Now use Collections.copy and note that b is still just a shallow copy of a
Collections.copy(b, a);
for (int i = 0; i < a.size(); i++) {
if (a.get(i) != b.get(i)) {
System.out.println("Oops, i was wrong this was a deep copy"); // Note this is never called.
}
}
// Now do a deep copy - requires you to explicitly copy each element
for (int i = 0; i < a.size(); i++) {
b.set(i, new String(a.get(i)));
}
// Now see that the elements are different in each
for (int i = 0; i < a.size(); i++) {
if (a.get(i) == b.get(i)) {
System.out.println("oops, i was wrong, a shallow copy was done."); // note this is never called.
}
}
}