开门见山的说,List的复制其实是很常见的,List其本质就是数组,而其存储的形式是地址
如图所示,将List A列表复制时,其实相当于A的内容复制给了B,java中相同内容的数组指向同一地址,即进行浅拷贝后A与B指向同一地址。
造成的后果就是,改变B的同时也会改变A,因为改变B就是改变B所指向地址的内容,由于A也指向同一地址,所以A与B一起改变。
这也就是List的浅拷贝,其常见的实现方式有如下几种:
浅拷贝
1、遍历循环复制
List<Person> destList=new ArrayList<Person>(srcList.size()); for(Person p : srcList){ destList.add(p); }
2、使用List实现类的构造方法
List<Person> destList=new ArrayList<Person>(srcList);
3、使用list.addAll()方法
List<Person> destList=new ArrayList<Person>(); destList.addAll(srcList);
4、使用System.arraycopy()方法
Person[] srcPersons=srcList.toArray(new Person[0]); Person[] destPersons=new Person[srcPersons.length]; System.arraycopy(srcPersons, 0, destPersons, 0, srcPersons.length);
测试及结果
printList(destList); //打印未改变B之前的A srcList.get(0).setAge(100);//改变B printList(destList); //打印改变B后的A //打印结果 123-->20 ABC-->21 abc-->22 123-->100 ABC-->21 abc-->22
List 深拷贝
如图,深拷贝就是将A复制给B的同时,给B创建新的地址,再将地址A的内容传递到地址B。ListA与ListB内容一致,但是由于所指向的地址不同,所以改变相互不受影响。
import org.apache.commons.collections.CollectionUtils; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class CopyTest { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(i); } //list深度拷贝 List<Integer> newList = new ArrayList<>(); CollectionUtils.addAll(newList, new Object[list.size()]); Collections.copy(newList, list); newList.set(0, 10); System.out.println("原list值:" + list); System.out.println("新list值:" + newList); } }
测试结果
原list值:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
新list值:[10, 1, 2, 3, 4, 5, 6, 7, 8, 9]
小结
Java对对象和基本的数据类型的处理是不一样的。在Java中用对象的作为入口参数的传递则缺省为”引用传递”,也就是说仅仅传递了对象的一个”引用”,这个”引用”的概念同C语言中的指针引用是一样的。当函数体内部对输入变量改变时,实质上就是在对这个对象的直接操作。 除了在函数传值的时候是”引用传递”,在任何用”=”向对象变量赋值的时候都是”引用传递”。
在浅复制的情况下,源数据被修改破坏之后,使用相同引用指向该数据的目标集合中的对应元素也就发生了相同的变化。因此,在需求要求必须深复制的情况下,要是使用上面提到的方法,请确保List中的T类对象是不易被外部修改和破坏的。