如何复制Java集合列表
我有一个如何复制Java集合列表,java,list,collections,copy,Java,List,Collections,Copy,我有一个ArrayList,我想准确地复制它。如果可能的话,我会使用实用程序类,前提是有人花了一些时间来纠正它。因此,很自然地,我最终得到了Collections类,它包含一个copy方法 假设我有以下几点: List<String> a = new ArrayList<String>(); a.add("a"); a.add("b"); a.add("c"); List<String> b = new ArrayList<String>(a.si
ArrayList
,我想准确地复制它。如果可能的话,我会使用实用程序类,前提是有人花了一些时间来纠正它。因此,很自然地,我最终得到了Collections
类,它包含一个copy方法
假设我有以下几点:
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);
List a=new ArrayList();
a、 添加(“a”);
a、 添加(“b”);
a、 添加(“c”);
列表b=新的ArrayList(a.size());
收藏。副本(b,a);
这失败了,因为它基本上认为b
不够大,无法容纳a
。是的,我知道b
的尺寸为0,但现在应该足够大了,不是吗?如果我必须先填写b
,那么Collections.copy()
在我的脑海中就成了一个完全无用的函数。那么,除了编程一个复制函数(我现在要做)之外,还有什么合适的方法可以做到这一点吗?只需执行以下操作:
List a = new ArrayList();
a.add("a");
a.add("b");
a.add("c");
List b = new ArrayList(a);
ArrayList具有一个构造函数,该构造函数将接受另一个集合来从b
复制元素,其容量为3,但大小为0。ArrayList
具有某种缓冲区容量这一事实是一个实现细节-它不是List
接口的一部分,因此Collections.copy(List,List)
不使用它。如果它使用特殊情况ArrayList
,那就太难看了
正如MrWiggles所指出的那样,在所提供的示例中,使用接受集合的ArrayList构造函数是实现此目的的方法
对于更复杂的场景(可能包括您的真实代码),您可能会发现其中的集合很有用。复制列表的最简单方法是将其传递给新列表的构造函数:
List<String> b = new ArrayList<>(a);
如果要复制ArrayList,请使用以下命令进行复制:
List b = new ArrayList();
b.add("aa");
b.add("bb");
List a = new ArrayList(b);
不设置大小。它设置初始容量(即在需要调整大小之前可以容纳多少个元素)。在这种情况下,一种更简单的复制方式是:
List b = new ArrayList(a);
如果您设想将一些值复制到现有集合中的用例,那么复制并不是无用的。即,您希望覆盖现有元素而不是插入 例如:a=[1,2,3,4,5]b=[2,2,2,3,3,3,3,3,4,4,4,]a.copy(b)=[1,2,3,4,5,3,3,3,4,4,4] 但是,我希望有一个copy方法,它将为源集合和目标集合的开始索引获取额外的参数,并为count获取一个参数 请参见Java错误调用
List<String> b = new ArrayList<String>(a);
还可以在b
中创建a
的浅拷贝。如果第一个参数b
没有足够的容量(而不是大小)来包含a
的所有元素,那么它将抛出索引自动边界异常。我们的期望是,不需要任何分配来工作,如果需要,则抛出该异常。要求对复制的集合进行预分配(b
)是一种优化,但我通常认为该功能不值得,因为考虑到基于构造函数的替代方案(如上图所示,没有奇怪的副作用)所需的检查
要创建深度副本,列表
,无论是通过哪种机制,都必须对底层类型有复杂的了解。对于String
s,它在Java(以及.NET)中是不可变的,您甚至不需要深度拷贝。对于MySpecialObject
,您需要知道如何对其进行深度复制,而这不是一般操作
注:最初接受的答案是集合的最高结果。在谷歌中复制,正如评论中指出的那样,它是完全错误的。斯蒂芬·卡图尔卡(接受的答案)的答案是错误的(第二部分)。
它解释了Collections.copy(b,a)代码>执行深度复制,但它不执行。两者,newarraylist(a)代码>和集合。副本(b,a)代码>仅进行浅层复制。不同之处在于,构造函数分配新内存,而copy(…)
不分配,这使得它适用于可以重用阵列的情况,因为它在那里具有性能优势
Java标准API试图阻止深度副本的使用,因为如果新的编码人员定期使用深度副本,这将是不好的,这也可能是默认情况下clone()
不公开的原因之一
Collections.copy(…)
的源代码可在第552行的以下位置查看:
如果需要深度复制,则必须在每个对象上使用for循环和clone()手动迭代项。可以使用
List<String> b = new ArrayList<String>(a);
List b=新的数组列表(a);
因为它们是不可变的。除-->之外的每一个对象都需要自己迭代和复制。正如hoijui提到的那样。从Stephen Katulka选择的答案包含有关Collections.copy的注释,该注释不正确。作者可能接受了它,因为第一行代码是他想要的副本。对Collections.copy的附加调用将再次复制。(导致复制发生两次)
下面是证明它的代码
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.
}
}
}
publicstaticvoidmain(字符串[]args){
列表a=新的ArrayList();
a、 添加(“a”);
a、 添加(“b”);
a、 添加(“c”);
列表b=新阵列列表(a);
System.out.println(“此行之后应该没有输出”);
//注意,b已经是a的浅拷贝;
对于(int i=0;i// note: instantiating with a.size() gives `b` enough capacity to hold everything
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b, a);
List<String> b = new ArrayList<String>(a);
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.
}
}
}
public class User implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private String user;
private String password;
...
@Override
public Object clone() {
Object o = null;
try {
o = super.clone();
} catch(CloneNotSupportedException e) {
}
return o;
}
}
public static void main(String[] args) {
List<User> userList1 = new ArrayList<User>();
User user1 = new User();
user1.setUser("User1");
user1.setPassword("pass1");
...
User user2 = new User();
user2.setUser("User2");
user2.setPassword("pass2");
...
userList1 .add(user1);
userList1 .add(user2);
List<User> userList2 = new ArrayList<User>();
for(User u: userList1){
u.add((User)u.clone());
}
//With this you can avoid
/*
for(User u: userList1){
User tmp = new User();
tmp.setUser(u.getUser);
tmp.setPassword(u.getPassword);
...
u.add(tmp);
}
*/
}
List a = new ArrayList();
a.add("1");
a.add("abc");
List b = b.addAll(listA);
//b will be 1, abc
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
List<String> b = Lists.newArrayList(a);
Copy [1, 2, 3] to [1, 2, 3] using copy constructor.
Copy [1, 2, 3] to (smaller) [4, 5]
java.lang.IndexOutOfBoundsException: Source does not fit in dest
at java.util.Collections.copy(Collections.java:556)
at com.farenda.java.CollectionsCopy.copySourceToSmallerDest(CollectionsCopy.java:36)
at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:14)
Copy [1, 2] to (same size) [3, 4]
source: [1, 2]
destination: [1, 2]
Copy [1, 2] to (bigger) [3, 4, 5]
source: [1, 2]
destination: [1, 2, 5]
Copy [1, 2] to (unmodifiable) [4, 5]
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableList.set(Collections.java:1311)
at java.util.Collections.copy(Collections.java:561)
at com.farenda.java.CollectionsCopy.copyToUnmodifiableDest(CollectionsCopy.java:68)
at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:20)
private List<Item> cloneItemList(final List<Item> items)
{
Item[] itemArray = new Item[items.size()];
itemArray = items.toArray(itemArray);
return Arrays.asList(itemArray);
}
List<String> b = Optional.ofNullable(a)
.map(list -> (List<String>) new ArrayList<>(list))
.orElseGet(Collections::emptyList);
List<String> b = Optional.ofNullable(a)
.map(List::stream)
.orElseGet(Stream::empty)
.collect(Collectors.toList())