Collections.copy问题

时间:2011-05-12 06:56:22

标签: java collections

我希望b1b2拥有自己的元素集,然后b1和b2应该在内存中有自己的元素,以便在修改b1 / b2时,其他元素不应受到影响

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);

我得到了这个例外:

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)

3 个答案:

答案 0 :(得分:10)

ArrayList(int)构造函数给出一个大小为0的List,它只确保在需要重新分配底层数组之前可以添加n个元素。

您可以更好地复制列表:

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

语义与第一次向每个数组添加buffer.size()空值并调用Collections.copy(b1,buffer);

时的语义相同

如果您想要深层复制(元素也被复制),您将必须单独处理每个元素

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

答案 1 :(得分:1)

Collections.copy(...) javadoc说明了这一点:

  

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

ArrayList(int)构造函数创建一个空列表,其 capacity (不是大小!)由参数给出。

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

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

你应该做的是:

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

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

答案 2 :(得分:1)

您需要每个元素的深层副本。没有标准的方法来实现这一点,因为深度复制可能涉及将嵌套引用复制到其他对象的(集合)。执行此操作的最佳方法是创建一个复制构造函数,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));
}

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

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

请注意,还存在可克隆的界面。我建议不要使用它,因为很容易在引用的类,集合和子类化中犯错误。复制构造函数更容易正确。请参阅this page进行一些确证。

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

此外,StephenC理所当然地指出我上面的例子是坚果。我同意,人们永远不会像这样“深度复制”整数,但是对于包含我认为是问题的集合/引用的自定义对象是有意义的。