浅拷贝因只复制引用地址而不复制对象本身,导致原对象与克隆对象共享可变引用类型(如list、map、date、数组等),修改一方会污染另一方;二维嵌套结构、方法传参、spring原型bean中均存在同类风险。

浅拷贝的引用复制本身不报错、不崩溃,但会在后续修改中悄然引发数据污染——根源在于“地址被复制了,对象没被复制”。
可变引用字段共享导致状态互相覆盖
当对象包含 List、Map、自定义可变类、Date、数组等可变引用类型 时,浅拷贝只复制字段里的内存地址,新旧对象指向同一块堆内存:
- 修改克隆对象的
list.add("admin"),原对象的 list 也多出一项 - 调用克隆对象的
address.setCity("Beijing"),原对象看到的城市同步变更 -
Date是可变类,cloneObj.getCreateTime().setTime(0)会把原始时间改成 Unix 零点
二维及嵌套结构放大风险
数组或集合中再嵌套对象,浅拷贝只作用于最外层:
-
Person[][] grid = original.clone()→grid[0]和original[0]是同一个Person[]实例 -
grid[0][0].setName("X")直接改的是 original 中那个 Person 对象 -
String[][]看似安全,是因为String不可变;换成StringBuilder[][]就立刻暴露问题
方法传参时的隐性共享
Java 方法参数传递本质是“引用地址的副本”,行为与浅拷贝一致:
- 在方法内执行
arr[0] = 100或list.clear(),原始数组/集合被真实修改 - 这并非 bug,而是语言机制决定的——只要没新建对象,就始终共享底层实例
- 若方法逻辑含排序、过滤、填充等原地操作,调用方需主动做防御性拷贝(如
Arrays.copyOf(arr, arr.length))
Spring 原型 Bean 也可能踩坑
即使标注 @Scope("prototype"),若框架内部用浅拷贝方式创建实例,而 Bean 内含可变成员(如 new HashMap()),多个实例仍可能共用同一份上下文:
bean1.getContext().put("k", "v1")bean2.getContext().put("k", "v2")- 若 context 字段未重建,两次 put 实际操作的是同一个 Map
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











