当前位置:  开发笔记 > 编程语言 > 正文

如何复制Java Collections列表

如何解决《如何复制JavaCollections列表》经验,为你挑选了9个好方法。

我有一个ArrayList,我想完全复制它.我假设有人花了一些时间使其正确,我尽可能使用实用程序类.很自然地,我最终得到了Collections一个包含复制方法的类.

假设我有以下内容:

List a = new ArrayList();
a.add("a");
a.add("b");
a.add("c");
List b = new ArrayList(a.size());

Collections.copy(b,a);

这失败了,因为基本上它认为b不够大a.是的,我知道b它的大小为0,但它现在应该足够大,不应该吗?如果我必须先填补b,那么Collections.copy()在我的脑海中就会成为一个完全没用的功能.所以,除了编写一个复制函数(我现在要做的)之外,还有一种正确的方法吗?



1> Jon Skeet..:

b有一个容量为3,但是大小为0的事实ArrayList具有某种缓冲能力是一个实现细节-它不是一部分List的接口,所以Collections.copy(List, List)不使用它.对于特殊情况来说,这将是丑陋的ArrayList.

正如MrWiggles所指出的那样,使用带有集合的ArrayList构造函数是提供的示例中的方法.

对于更复杂的场景(可能包括您的真实代码),您可能会发现Google Java Collections库非常有用.


@Pacerier:我从事过移动同步,通过APNS的iPhone通知,Windows Phone 7 Google搜索应用和Android Market.

2> 小智..:

调用

List b = new ArrayList(a);

创建一个浅的a内部副本b.所有元素都将以b与它们所在的完全相同的顺序存在a(假设它有一个订单).

同样,打电话

// note: instantiating with a.size() gives `b` enough capacity to hold everything
List b = new ArrayList(a.size());
Collections.copy(b, a);

还会创建一个a内部的浅表副本b.如果第一个参数,b没有足够的容量(不是大小)来包含所有a的元素,那么它将抛出一个IndexOutOfBoundsException.期望是工作不需要任何分配Collections.copy,如果有,则抛出该异常.要求复制的集合被预先分配(b)是一种优化,但我通常不认为该特征是值得的,因为给定基于构造函数的替代方案所需的检查,如上所示,没有任何奇怪的副作用.

要创建深层副本,List通过任一机制,都必须具有基础类型的复杂知识.对于Strings,它在Java(以及.NET)中是不可变的,你甚至不需要深层复制.在这种情况下MySpecialObject,您需要知道如何制作它的深层副本,这不是一般操作.


注意:最初接受的答案是Collections.copy谷歌的最高结果,如评论中所指出的那样,这是错误的.


这个答案是完全错误的.要进行深层复制,必须(1)为旧列表中的每个元素创建一个新列表(2),制作该元素的深层副本并将其添加到新列表中.Java中有*no*内置函数来执行深层复制.每个对象的copy()方法(从类Object扩展)*不执行深层复制.copy()必须由类作者实现.
这仍然是一个浅薄的副本!
在个人方面,我发现这个问题是Java的一个严重缺点 - 事实上没有内置的深拷贝功能(即将对象x的字节复制到内存中的新位置并给我一个参考那个新深度复制的对象).

3> tddmonkey..:

做就是了:

List a = new ArrayList(); 
a.add("a"); 
a.add("b"); 
a.add("c"); 
List b = new ArrayList(a);

ArrayList有一个构造函数,它将接受另一个Collection来复制元素


对于字符串列表,深度复制并不重要,因为`String`对象是不可变的.
作为评论下方的人,这是一个浅薄的副本.否则,这将是一个很好的答案.我想我应该指明这一点.没关系,我还是继续前进.

4> hoijui..:

Stephen Katulka(接受的答案)的回答是错误的(第二部分).它解释说它Collections.copy(b, a);是一个深层复制,它没有.这两种,new ArrayList(a);Collections.copy(b, a);只能做一个浅拷贝.区别在于,构造函数分配新内存,而copy(...)不是,这使得它适用于可以重用数组的情况,因为它具有性能优势.

Java标准API试图阻止使用深层副本,因为如果新编码器会定期使用它,这将是不好的,这也可能clone()是默认情况下不公开的原因之一.

源代码Collections.copy(...)可以在第552行看到:http: //www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/ Collections.java.htm

如果需要深层复制,则必须手动迭代项目,对每个对象使用for循环和clone().



5> Gareth Davis..:

复制List的最简单方法是将其传递给新列表的构造函数:

List b = new ArrayList<>(a);

b 将是一个浅薄的副本 a

看看Collections.copy(List,List)(我以前从未见过它)的来源似乎是通过索引来处理元素索引.使用List.set(int,E)因此元素0将覆盖目标列表等中的元素0等.从javadocs我不得不承认不是特别清楚.

List a = new ArrayList<>(a);
a.add("foo");
b.add("bar");

List 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'


通过"浅拷贝",他意味着在复制之后,b中的对象与a中的对象相同,而不是它们的副本.

6> cletus..:
List b = new ArrayList(a.size())

没有设置大小.它设置初始容量(在需要调整大小之前它可以容纳多少元素).在这种情况下,一种更简单的复制方法是:

List b = new ArrayList(a);



7> Michael Welc..:

正如hoijui提到的那样.Stephen Katulka的选定答案中包含有关Collections.copy的评论不正确.作者可能接受了它,因为第一行代码正在执行他想要的副本.对Collections.copy的额外调用只会再次复制.(导致复制发生两次).

这是代码来证明它.

public static void main(String[] args) {

    List a = new ArrayList();
    a.add("a");
    a.add("b");
    a.add("c");
    List b = new ArrayList(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.
        }
    }
}



8> 小智..:

这里的大多数答案没有意识到问题,用户想要从第一个列表到第二个列表的元素的COPY,目的地列表元素是新对象而不是引用原始列表的元素.(意味着更改第二个列表的元素不应该更改源列表的相应元素的值.)对于可变对象,我们不能使用ArrayList(Collection)构造函数,因为它将简单地引用原始列表元素而不会复制.复制时,每个对象都需要有一个列表克隆器.



9> Vin.X..:

为什么不使用addAll方法:

    List a = new ArrayList();
         a.add("1");
         a.add("abc");

    List b = b.addAll(listA);

//b will be 1, abc

即使您在b中有现有项目,或者想要在其后面放置一些元素,例如:

List a = new ArrayList();
     a.add("1");
     a.add("abc");

List b = new ArrayList();
     b.add("x");
     b.addAll(listA);
     b.add("Y");

//b will be x, 1, abc, Y

推荐阅读
凹凸曼00威威_694
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有