Java中ArrayList默认浅拷贝,深拷贝需确保元素独立复制:基本类型包装类可直接引用;自定义对象需实现Cloneable、拷贝构造器等;序列化方式通用但有性能和兼容性限制。

Java 中的 ArrayList 默认是浅拷贝,直接用构造方法(如 new ArrayList(original))或 clone() 只会复制引用,不会复制元素对象本身。要实现深拷贝,必须确保集合中每个元素也被独立复制。
确认元素类型是否支持深拷贝
深拷贝的前提是集合中每个元素自身能被完整复制。常见情况:
- 元素是基本类型包装类(
Integer、String等):它们是不可变对象,直接复制引用即可视为“逻辑深拷贝”; - 元素是自定义对象:该类需提供深拷贝能力,例如实现
Cloneable并重写clone(),或提供拷贝构造器、静态工厂方法; - 元素是其他集合或含可变状态的对象:需逐层保证其内部字段也被深拷贝。
使用拷贝构造器或工厂方法(推荐)
如果元素类提供了拷贝构造器(如 new Person(p)),最清晰安全的方式是遍历原集合,逐一创建新对象:
<font color="#888"><pre class="brush:php;toolbar:false;">List<person> original = ...;
List<person> deepCopy = original.stream()
.map(Person::new) // 假设 Person 有 Person(Person p) 构造器
.collect(Collectors.toList());</person></person>
或者用传统 for 循环:
<font color="#888"><pre class="brush:php;toolbar:false;">List<person> deepCopy = new ArrayList();
for (Person p : original) {
deepCopy.add(new Person(p)); // 调用拷贝构造器
}</person>
借助序列化实现通用深拷贝(慎用)
适用于所有实现了 Serializable 的元素类型,无需修改类定义,但有局限性:
- 所有嵌套字段(包括父类、集合内对象)都必须可序列化;
- 含
transient字段或不可序列化资源(如 IO 流、线程、Socket)会丢失或抛异常; - 性能较差,仅适合低频、小数据量场景。
示例工具方法:
<font color="#888"><pre class="brush:php;toolbar:false;">public static <t extends serializable> List<t> deepCopyBySerialization(List<t> src) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis)) {
oos.writeObject(src);
return (List<t>) ois.readObject();
} catch (Exception e) {
throw new RuntimeException("Deep copy failed", e);
}
}</t></t></t></t>
避免踩坑:clone() 和 Collections.copy 不行
不要依赖 ArrayList.clone() —— 它返回的是浅拷贝,内部数组元素仍是原对象引用。
不要用 Collections.copy(dest, src) —— 目标列表必须已初始化且长度足够,且仍是浅拷贝。
两者对含可变对象的 ArrayList 都无法防止修改副本影响原集合。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











