前言:
区别:
浅拷贝:直接引用原对象的内存地址,导致修改复制后的对象,原对象也被修改
深拷贝:重新在栈、堆中开辟空间,内存地址不一样,内部存放的数据一样,修改复制后的对象,原对象不会影响。
那么本文就是针对常见的针对集合、map的复制方法,探究他们是浅拷贝还是深拷贝!
集合的浅、深拷贝
1. 浅拷贝:BeanUtils.copyProperties:
该方法首先是不能复制集合的:
其次该方法是浅拷贝:
接着
不管是:org.springframework.beans.BeanUtils
还是:org.apache.commons.beanutils.BeanUtils
都是浅拷贝
2. 浅拷贝:Collections.copy
//测试3: Collections.copy(list2, list1);
List<Student> list1 = new ArrayList<>();
List<Student> list2 = new ArrayList<>();
for (int i = 0; i < 1; i++) {
list2.add(null); // 必须手动把list2的长度增加到10,否则拷贝了之后list2长度仍是0
}
for (int i = 0; i < 1; i++) {
Student student = new Student(i, "a");
list1.add(student);
}
System.out.println("List1:"+ list1);
list1.stream().forEach(System.out::println);
Collections.copy(list2, list1);
System.out.println("List2:" + list2);
list2.stream().forEach(System.out::println);
list1.get(0).setName("测试");
System.out.println("List1修改之后:" );
list1.stream().forEach(System.out::println);
System.out.println("List2在list1修改之后:" );
list2.stream().forEach(System.out::println);
注意:
BeanUtils.copyProperties(list1, list2); 若list2的长度为空吗,则复制后list2还是为空,需要你手动吧list的长度填充为list1长度一样。【我觉得这里巨离谱】
3. 浅拷贝:List target = new ArrayList<>(listSource)
同样是浅拷贝
4. 深拷贝:序列化的方式
序列化的方式可以实现深拷贝,代码如下:
public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
List<T> copy_list = (List<T>) in.readObject();
return copy_list;
}
不知道你觉得麻不麻烦?所以一下给出用Stream流的方式实现集合的深拷贝、
5. 深拷贝:Stream流
List<Student> list2 = new ArrayList<>();
list1.stream().forEach(item->{
//每一次new 一个新的对象放进去就行了
Student student = new Student();
BeanUtils.copyProperties(student,item);
list2.add(student);
});
个人理解:深拷贝不就是使得拷贝后的元素的地址指向和拷贝前的地址不一样嘛,那直接每次new一个对象放进去就行了
map的浅、深拷贝
1. 浅拷贝:= 方式
2. 特殊情况:putall的方式
首先putall,对于map内部存放的内容来说是浅拷贝,但是一般写程序的时候,map内部的引用对象一般不会修改的吧,所以如果存在map拷贝的情况,在对于map内部的对象不存在修改的情况下是可以使用的。
其次假如真有修改内部对象的需求,那么可以采用Stream流的方式,在拷贝对象的时候,new 1个新对象放进map中