Java深拷贝和浅拷贝原理
源头
最近项目中想要实现一个功能,根据一个统计的java模版,统计的参数基本初始化都为0,针对每次不同的查询条件,查询出来的不同记录,然后修改部分值,但是发现每次查询出来的不同记录会影响到模版类数据的变化。
问题复现
/**
* 统计不同部门人数
*/
@Data
public class CountEmpModel {
// 部门名称
private String department;
// 男性人数
private Integer male = 0;
// 女性人数
private Integer female = 0;
// 不同岗位的人数
private CountPostModel countPostModel;
}
/**
* 统计不同岗位人数
*/
@Data
public class CountPostModel {
// 岗位id
private String postId;
// 岗位名称
private String postName;
// 岗位人数
private Integer postNum;
}
操作:
public static void main(String[] args) {
// 初始化模版countEmpTemplate
CountEmpModel countEmpTemplate = new CountEmpModel();
CountPostModel countPostModel = new CountPostModel();
countPostModel.setPostId(null);
countPostModel.setPostName(null);
countPostModel.setPostNum(0);
countEmpTemplate.setFemale(0);
countEmpTemplate.setMale(0);
countEmpTemplate.setDepartment(null);
countEmpTemplate.setCountPostModel(countPostModel);
// 创建查询后返回前端的对象countEmpModel1
CountEmpModel countEmpModel1 = new CountEmpModel();
// 使用模版类初始化countEmpModel1
BeanUtil.copyProperties(countEmpTemplate, countEmpModel1);
// 查询到值之后,赋值给返回前端的对象countEmpModel1
countEmpModel1.setFemale(100);
countEmpModel1.setMale(100);
countEmpModel1.setDepartment("科技部门");
CountPostModel countPostModel1 = countEmpModel1.getCountPostModel();
countPostModel1.setPostId("1111");
countPostModel1.setPostName("岗位1");
countPostModel1.setPostNum(30);
// 查看模版类是否发生变化
System.out.println(countEmpTemplate.getDepartment());
System.out.println(countEmpTemplate.getFemale());
System.out.println(countEmpTemplate.getMale());
System.out.println(countEmpTemplate.getCountPostModel().getPostId());
System.out.println(countEmpTemplate.getCountPostModel().getPostName());
System.out.println(countEmpTemplate.getCountPostModel().getPostNum());
}
结果:模版类发生了变化
到底什么是浅拷贝和深拷贝
- 浅拷贝:针对引用类型,目标对象拷贝的只是源对象的地址,无论目标对象还是源对象改变,他们都会一起改变。
- 深拷贝:将源对象复制一份给目标对象,二者没有任何关系。
- 注意:浅拷贝还是深拷贝都是针对引用类型,而基本数据类型和String类型是不会发生变化的。
BeanUtils.copyProperties是浅拷贝还是深拷贝?
上面的实验看出BeanUtils.copyProperties是浅拷贝。
如何实现深拷贝?
/**
* 深拷贝
* @param source
* @param <S>
*/
public static <S extends Serializable, T extends Serializable> void copyBeanByDeep(S source, T dest) {
ObjectOutputStream obs = null;
ObjectInputStream os = null;
try {
//写入字节流
ByteArrayOutputStream out = new ByteArrayOutputStream();
obs = new ObjectOutputStream(out);
obs.writeObject(source);
//分配内存,写入原始对象,生成新对象
ByteArrayInputStream is = new ByteArrayInputStream(out.toByteArray());
os = new ObjectInputStream(is);
S s = (S) os.readObject();
BeanUtils.copyProperties(s, dest);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
try {
if (obs != null) {
obs.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
测试深拷贝
public static void main(String[] args) {
// 初始化模版countEmpTemplate
CountEmpModel countEmpTemplate = new CountEmpModel();
CountPostModel countPostModel = new CountPostModel();
countPostModel.setPostId(null);
countPostModel.setPostName(null);
countPostModel.setPostNum(0);
countEmpTemplate.setFemale(0);
countEmpTemplate.setMale(0);
countEmpTemplate.setDepartment(null);
countEmpTemplate.setCountPostModel(countPostModel);
// 创建查询后返回前端的对象countEmpModel1
CountEmpModel countEmpModel1 = new CountEmpModel();
// 使用模版类初始化countEmpModel1
CopyUtils.copyBeanByDeep(countEmpTemplate, countEmpModel1);
// BeanUtil.copyProperties(countEmpTemplate, countEmpModel1);
// 查询到值之后,赋值给返回前端的对象countEmpModel1
countEmpModel1.setFemale(100);
countEmpModel1.setMale(100);
countEmpModel1.setDepartment("科技部门");
CountPostModel countPostModel1 = countEmpModel1.getCountPostModel();
countPostModel1.setPostId("1111");
countPostModel1.setPostName("岗位1");
countPostModel1.setPostNum(30);
// 查看模版类是否发生变化
System.out.println(countEmpTemplate.getDepartment());
System.out.println(countEmpTemplate.getFemale());
System.out.println(countEmpTemplate.getMale());
System.out.println(countEmpTemplate.getCountPostModel().getPostId());
System.out.println(countEmpTemplate.getCountPostModel().getPostName());
System.out.println(countEmpTemplate.getCountPostModel().getPostNum());
}
结果:模版类没有受到影响