繁体   English   中英

将列表的元素添加到Java中的相同列表

[英]Add elements of a list to the same list in java

是否可能以下情况? 如果是,它是否有任何缺点,或者有更好的方法吗?

List<Integer> myList = new ArrayList<>();
myList.add(2);
myList.add(3);

// then add all the elements again
myList.add(myList);

ArrayListaddAll方法恰好在Oracle的JDK(和OpenJDK)中工作。 但这并不能保证。 addAllJavadoc说:

如果在操作进行过程中修改了指定的集合,则此操作的行为是不确定的。 (这意味着如果指定的集合是此列表,并且此列表是非空的,则此调用的行为是不确定的。)

实际上,这个问题并不像某些答案所暗示的那样毫无意义。 正如这种情况所证明的那样,仅“尝试”还不足以证明某些东西正常工作。

实际上,在考虑list.addAll(list)是否有效时,您需要问自己如何实现。 如果只是简单地遍历list并将每个元素添加到list的末尾,则将得到ConcurrentModificationException (否则它将陷入无限循环)。 这就是Javadoc不保证此类调用有效的原因。 碰巧的是,Oracle的实现首先将传递的列表复制到数组,然后将数组的每个元素复制到列表的末尾。 这意味着对列表调用addAll可能不如自己创建列表而不创建额外副本那样有效。

对于基本数据类型(布尔,短,整数,长,浮点,双精度,字符串),它们是不可变的,这意味着它们将始终按值传递。

Integer X = 10;
Integer Y = X; // Y is 10, X is 10
Y = 20;        // Y is 20, X is 10
X = 30;        // Y is 20, X is 30

String A = "Test";
String B = A; // B is a copy of A; A & B are distinct

但是,当存储对象时会出现问题,如果尝试分配,最终将复制引用而不是复制值。

Object C = new Object();
Object D = C; // C & D points at the same object

最佳实践是复制,否则,如果使用对象,则最终将获得对同一对象的多个引用。

class MyObj { private int val; public MyObj(int v){ val=v; } ..}

ArrayList<MyObj> list = new ArrayList<MyObj>();
list.add(new MyObj(2));
list.add(new MyObj(3));

list.addAll(list);

您可能会认为列表现在有4个对象,除非您错了,它有2个对2个不同对象的引用,一个简单的测试将演示如何。

// prints: 2 3 2 3
for(MyObj m : list) System.out.print(" "+m.getVal());

// modify first item to 5
list.get(0).setVal(5);

// prints: 5 3 5 3
for(MyObj m : list) System.out.print(" "+m.getVal());

您可以通过手动创建和启动对象来克隆对象。

int oldSize = list.size();
for(int i=0; i<oldSize; i++)
{
    MyObj m = list.get(i);
    MyObj t = new MyObj();
    t.setVal(m.getVal());
    list.add(t); // append
}

您也可以有一个复制构造函数,然后将要克隆的对象传递给它。

class MyObj
{
    ..
    public MyObj(MyObj o)
    {
        val = o.getVal();
    }
}

int oldSize = list.size();
for(int i=0; i<oldSize; i++)
{
    MyObj m = list.get(i);
    list.add(new MyObj(m)); // append
}

此外,您的对象类可以实现接口Cloneable并扩展clone方法。

class MyObj implements Cloneable
{
    ..
    public Object clone() throws CloneNotSupportedException
    {  
        return (MyObj)super.clone();
    }
}

int oldSize = list.size();
for(int i=0; i<oldSize; i++)
{
    MyObj m = list.get(i);
    list.add(m.clone()); // append
}

myList.add(myList);的主要缺点 是它不会编译,因为myList不是Integer

但是,您可以使用:

myList.addAll(myList);

Ideone演示

要么

myList.addAll(new ArrayList<>(myList));

如果您想安全地这样做。

myList.addAll(myList);

=>有效。

myList.add(myList); 

=>无法编译,.add方法需要一个Integer(不是int)作为参数,您不能使用另一个List进行调用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM