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

ArrayList 的 clone() 方法执行的是**浅拷贝**,它只复制了 ArrayList 实例本身(如 size、elementData 数组引用等字段),但不复制数组中每个元素对象的内容;而数组本身的复制(如 Arrays.copyOf() 或 System.arraycopy())也属于浅拷贝——只是复制引用,不是对象实例。
clone() 浅拷贝的具体行为
调用 list.clone() 会创建一个新的 ArrayList 实例,其 size 和内部 elementData 数组长度与原列表一致,且数组中每个元素的引用值被逐个复制过去。这意味着:
- 新旧 ArrayList 是两个独立对象(
==为 false,equals()可能为 true) - 它们的
elementData数组是不同数组对象(内存地址不同) - 但数组中存的如果是自定义对象引用,新旧数组指向的是同一组对象实例
- 修改新列表的结构(add/remove)不影响原列表;但修改某个共用对象的状态,两边都可见
数组复制也是浅拷贝
ArrayList 内部常用 Arrays.copyOf(elementData, newCapacity) 扩容,或用 System.arraycopy() 移动元素。这些操作复制的是引用值,不是对象本身:
- 对
String、Integer等不可变类型,效果上“像”深拷贝(因无法修改其状态) - 对可变对象(如
StringBuilder、自定义User类),新旧数组共享同一对象引用 - 例如:
list1.get(0).setName("Alice")后,list2.get(0).getName()也会返回 "Alice"
如何实现真正的深拷贝
Java 没有内置通用深拷贝机制,需手动处理。常见方式有:
立即学习“Java免费学习笔记(深入)”;
-
实现 Cloneable + 重写 clone():在元素类中递归克隆,ArrayList 中遍历调用每个元素的
clone() -
构造新对象赋值:遍历原列表,用构造函数或 builder 创建新实例,如
new User(u.getName(), u.getAge()) -
序列化反序列化(适用于可序列化类):用
ObjectOutputStream写入字节流再读回,绕过引用共享 -
第三方库辅助:如 Apache Commons Lang 的
SerializationUtils.clone(),或 MapStruct、Dozer(适合复杂对象图)
实际使用建议
多数场景下浅拷贝已足够——尤其元素是不可变类型或仅需隔离容器结构时。若需深拷贝,优先考虑明确构造新对象,而非依赖序列化(性能低、要求 Serializable、可能抛异常)。不要误以为 clone() 能自动深拷贝内容,这是常见误区。


















