Java中ArrayList所有复制方法均为浅拷贝,仅复制容器不复制元素引用;若元素为可变对象,修改副本会影响原列表;深拷贝需逐元素克隆、拷贝构造、序列化或第三方工具,关键在元素级复制。

Java 中 ArrayList 的 clone()、构造函数(new ArrayList(list))、addAll() 或 Stream 收集等方法,**全部只做浅拷贝**——它们新建了 List 容器,但容器内每个元素仍指向原对象的同一内存地址。若元素是可变对象(如自定义类、StringBuilder、HashMap),修改副本中某个元素的状态,原列表也会同步变化。
为什么浅拷贝不够用?
例如:
- 原列表含
new User("Alice", 25),副本也引用这个User实例 - 执行
copyList.get(0).setAge(30)后,原列表对应元素的 age 也变成 30 - 只有元素是不可变类型(
String、Integer)时,浅拷贝才“看起来安全”
手动逐元素克隆(推荐用于可控结构)
前提是元素类已正确实现 Cloneable 并重写 clone(),且该方法递归处理了所有可变字段:
- 定义
User implements Cloneable,clone()中对姓名、地址等引用字段也调用其clone() - 复制代码:
List<User> deepCopy = new ArrayList<>();<br>for (User u : original) {<br> deepCopy.add(u.clone());<br>}
使用构造函数或 Builder 创建新实例(更清晰、更可控)
不依赖 clone() 机制,避免接口和异常约束,适合多数业务场景:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
立即学习“Java免费学习笔记(深入)”;
- 为
User添加带参构造函数:User(User src)或User copy() - 或使用 Lombok 的
@Builder+toBuilder = true - 复制代码:
List<User> deepCopy = original.stream()<br> .map(User::new) // 调用拷贝构造<br> .collect(Collectors.toList());
序列化反序列化(适合嵌套深、难改源码的场景)
天然绕过引用共享,但有硬性前提:
- 列表中所有元素类及其所有字段类型都必须实现
Serializable - 不能含
transient重要字段,也不能含不可序列化资源(如 IO 流、线程) - 性能开销较大,仅建议在无法修改元素类或结构极复杂时采用
第三方工具辅助(谨慎评估依赖)
如 Apache Commons Lang 的 SerializationUtils.clone() 就是封装了上述序列化逻辑;MapStruct 等映射框架适合 DTO 层转换,但不属于通用深拷贝方案。
真正深拷贝的关键不在“怎么复制 List”,而在于“如何复制它的每个元素”。没有银弹,需根据元素类是否可控、嵌套深度、性能要求来选型。多数情况下,显式构造新对象比依赖 clone() 更可靠、更易维护。

















