ArrayList的clone()方法是浅拷贝,因为它仅创建新ArrayList实例并复制elementData数组引用,不复制数组中可变元素对象本身;新旧列表共享同一组对象实例,修改共用对象状态会相互影响。

ArrayList 的 clone() 方法是浅拷贝。
为什么 clone() 是浅拷贝
调用 list.clone() 会创建一个新的 ArrayList 实例,但只复制了内部 elementData 数组的引用值,数组中每个元素的对象本身并未被复制。这意味着:
- 新旧 ArrayList 是两个不同的对象(
==为 false) - 它们的底层数组是不同对象(内存地址不同)
- 但数组中存放的如果是可变对象(如自定义类、HashMap、StringBuilder),新旧列表仍指向同一组对象实例
- 修改某个共用对象的状态(例如
list2.get(0).setName("Alice")),原列表也会看到变化
哪些方式同样是浅拷贝
以下常见写法和 clone() 行为一致,都只复制引用:
new ArrayList(original)list2.addAll(list1)-
Collections.copy(dest, src)(要求 dest 已有容量) list.stream().collect(Collectors.toList())
这些操作都不会触发元素对象本身的复制,只是新建容器并填充相同引用。
立即学习“Java免费学习笔记(深入)”;
什么时候浅拷贝就足够了
当 ArrayList 中的元素全是不可变类型时,浅拷贝在效果上等同于深拷贝:
-
String、Integer、Long、LocalDate等不可变类,其状态无法被修改 - 即使新旧列表共享引用,也无法通过任一列表改变对象内容
- 这也是算法题中常用
clone()或构造函数的原因——输入多为基本包装类或字符串
如何实现真正的深拷贝
Java 没有通用自动深拷贝机制,需根据场景手动处理:
-
逐个克隆元素:要求元素类实现
Cloneable并重写clone(),再遍历调用:List<MyObj> deep = new ArrayList<>();<br>for (MyObj o : original) deep.add(o.clone());
- 构造新对象:用构造函数或 builder 创建副本,更可控、更易读
-
序列化反序列化:适用于所有可序列化(
Serializable)且无transient敏感字段的类,但性能低、有异常风险 -
第三方工具:如 Apache Commons Lang 的
SerializationUtils.clone(),或 MapStruct(适合 DTO 转换)
注意:“深”的边界由你定义——是否递归克隆嵌套对象(如 Person 中的 Address 字段),取决于业务需求和对象结构。


















