java中arraylist默认浅拷贝,仅复制容器引用;深拷贝需确保元素也被独立复制,方法包括手动clone、序列化或拷贝构造器,选择取决于元素可变性与复制需求。

Java 中 ArrayList 的拷贝默认都是浅拷贝,深拷贝需要额外处理——关键不在容器本身,而在它装的元素是否被真正复制。
浅拷贝:只复制容器,不复制内容
以下方式都属于浅拷贝,它们新建了 ArrayList 实例,但内部元素仍指向原对象:
- ArrayList.clone():返回 Object,需强制转型;仅复制内部 Object[] 数组引用,元素对象未复制
- new ArrayList(otherList):构造函数创建新容器,逐个添加原列表元素引用
- Collections.copy(dest, src):要求 dest 已有容量,仍是按索引赋值引用
- stream().collect(toList()):本质是遍历 + add,同样只传递引用
适用场景:元素全是不可变类型(如 String、Integer、LocalDateTime),此时浅拷贝行为上等价于深拷贝,安全且高效。
深拷贝:必须让每个可变元素也独立
深拷贝没有通用银弹,取决于元素类型是否支持复制,常见做法有:
-
手动逐个 clone:要求元素类实现 Cloneable 并重写 clone() 方法
示例:list.stream().map(e -> e.clone()).collect(Collectors.toList()) -
使用序列化反序列化:绕过 Cloneable 限制,适合无法修改源码或嵌套深的场景
前提:所有元素及其字段都实现 Serializable,且不含 transient 关键数据 -
拷贝构造器或工厂方法:为自定义类提供
public MyClass(MyClass other),在构造中递归复制字段
注意:如果元素的 clone() 方法没递归处理其内部引用字段(比如一个 Map 字段没 clone),那仍是浅的——“深”的程度由你控制。
为什么 new ArrayList 就不是深拷贝?
因为 new 只负责分配容器内存,不干预元素。就像买了一个新盒子,把旧盒子里的书直接搬进去——书还是同一本,改一页,两边都看到变化。只有把每本书复印一份再装进去,才算深拷贝。
怎么选?看实际需求
如果只是临时读取、元素不可变,用 new ArrayList(list) 最简洁;
如果要修改副本中的对象且不影响原列表,必须确保元素也被复制——优先检查是否已有 clone() 或构造器支持,否则考虑序列化方案。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











