先说定义,
浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
深拷贝与浅拷贝是针对对象属性为对象的,因为基本数据类型在进行赋值操作时(也就是深拷贝(值拷贝)),是直接将值赋给了新的变量,也就是该变量是原变量的一个副本,这时,你修改两个中的任意一个都不会影响另一个;而对于对象或引用数据在进行浅拷贝时,只是将对象的引用复制了一份,也就是内存地址,即两个不同的变量指向了同一个内存地址,那么在改变任意一个变量的值都是改变内存地址所存储的值,因此两个变量的值都会改变。
简单来说,两者实际上都是为目标对象赋值,浅拷贝复制的是基本数据类型的数据以及引用类型的地址值,对于引用类型实际上是共用一个地址值(个人理解),深拷贝对于基本数据类型一样,对于引用类型是重新new了一个新对象并复制,用的是新的地址
举例:在项目中,我们常用beanUtils.copyProperties(),(不管是spring自带的还是apache的,都一样)来给具有较多相同字段的对象赋值,避免通过set的方式,开发效率较低过于繁琐,但是在bean对象结构较复杂,层级较多时会有一些问题,如下:
我先定义一个User实体
@Data
public class User {
private String username;
private String password;
private Address address;
@Data
public static class Address {
private Integer menpaihao;
private String jiedao;
private List<Integer> numList;
}
}
然后进行测试
@Test
public void Test(){
User user = new User();
user.setUsername("张三");
user.setPassword("123");
User.Address address = new User.Address();
address.setMenpaihao(110);
address.setJiedao("成华大道");
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
address.setNumList(list);
user.setAddress(address);
User user1 = new User();
BeanUtils.copyProperties(user,user1);
System.out.println("user1 = " + user1);
System.out.println("user = " + user);
User user2 = initUser(user1);
System.out.println("user = " + user);
System.out.println("user2 = " + user2);
System.out.println(VM.current().addressOf(user));
System.out.println(VM.current().addressOf(user2));
System.out.println("user的Address地址值 = " + VM.current().addressOf(user.getAddress()));
System.out.println("user2的Address的地址值 = " + VM.current().addressOf(user2.getAddress()));
}
public User initUser(User user){
List<Integer> numList = user.getAddress().getNumList();
for (int i = 0; i < numList.size(); i++) {
numList.set(i,0);
}
return user;
}
测试结果
可以发现将User复制到User1之后,我再对User1进行修改,改变它属下的numList里面的值,(而源对象User我一直是没有动过的),这时候再对两个进行打印,发现源对象User里面的属性值也被修改了,所以还是有点问题的。此时虽然最外层属性值没问题,地址也不一样,但是最内层的Address属性地址值是共用的,所以一变都变。
目前我的解决方式有两种,一种是老老实实通过set的方式一一赋值,效率还高,另一种就是通过深拷贝了。
深拷贝举例其中一种较简单的方式:
1. 导入依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
2. 对bean对象以及其引用的其他实体类对象都要实现序列化
3.使用SerializationUtils.clone()克隆,返回的对象就是克隆后的对象