以下是否可能?如果是,它有任何缺点或有更好的方法吗?
List<Integer> myList = new ArrayList<>();
myList.add(2);
myList.add(3);
// then add all the elements again
myList.add(myList);
答案 0 :(得分:3)
addAll
的{{1}}方法恰好在Oracle的JDK(和OpenJDK)中有效。但不能保证。 Javadoc for addAll
说:
如果在操作过程中修改了指定的集合,则此操作的行为是不确定的。 (这意味着如果指定的集合是此列表,则此调用的行为是未定义的,并且此列表是非空的。)
这个问题实际上并不像一些答案所暗示的那样毫无意义。正如本例所证明的那样,仅仅“尝试它”并不足以让某些东西正确运行。
事实上,在考虑ArrayList
是否有效时,您需要问问自己如何实施。如果它只是迭代list.addAll(list)
并将每个元素添加到list
的末尾,那么您将获得list
(否则它将进入无限循环)。这就是为什么Javadoc不保证这样的调用有效的原因。碰巧,Oracle的实现首先将传递的列表复制到数组,然后将数组的每个元素复制到列表的末尾。这意味着为列表调用ConcurrentModificationException
可能不如在不创建额外副本的情况下自行完成。
答案 1 :(得分:2)
对于基本数据类型(Boolean,Short,Integer,Long,Float,Double,String),它们是不可变的,这意味着它们将始终按值传递。
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个不同的对象,一个简单的测试将显示如何。
// 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
}
答案 2 :(得分:1)
myList.add(myList);
的主要缺点是它无法编译,因为myList
不是Integer
。
但是,您可以使用:
myList.addAll(myList);
或
myList.addAll(new ArrayList<>(myList));
如果你想安全地做到这一点。
答案 3 :(得分:0)
myList.addAll(myList);
=&GT;的工作原理。
myList.add(myList);
=&GT;不会编译,.add方法需要一个Integer(不是int)作为参数,你不能使用另一个List调用。