Java对象拷贝分浅拷贝和深拷贝:浅拷贝仅复制基本类型值和引用地址,深拷贝递归复制所有引用对象;浅拷贝常用实现Cloneable接口并重写clone()方法,深拷贝可选手动克隆、序列化、JSON工具或第三方库。

Java 中对象的拷贝分为浅拷贝和深拷贝,核心区别在于:浅拷贝只复制对象本身(基本类型值直接复制,引用类型只复制地址),深拷贝则递归复制所有引用指向的对象,确保新旧对象完全独立。
浅拷贝的实现方式
最常用的是实现 Cloneable 接口并重写 clone() 方法。注意:Object.clone() 默认行为就是浅拷贝。
- 类必须实现
Cloneable接口(否则抛CloneNotSupportedException) - 重写
clone()方法,调用super.clone() - 对于包含可变引用字段(如
List、自定义对象等),需手动处理才能变成深拷贝
示例:
class Person implements Cloneable {String name;
Address address; // 引用类型
public Person clone() {
try {
return (Person) super.clone(); // 浅拷贝:address 引用未变
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
深拷贝的常见实现方法
没有通用一键深拷贝机制,需根据场景选择合适方式:
立即学习“Java免费学习笔记(深入)”;
-
手动克隆:在
clone()中对每个引用字段调用其自身的clone()或新建对象赋值(适合结构稳定、字段少的类) - 序列化反序列化:将对象转为字节流再还原,天然实现深拷贝(要求所有字段类型都可序列化,且性能略低)
-
JSON 工具库(如 Jackson / Gson):先序列化成 JSON 字符串,再反序列化为新对象(简单易用,但要求类有无参构造器、字段可访问,且不支持某些特殊类型如
Thread、InputStream) -
第三方库(如 Apache Commons Lang 的
SerializationUtils):封装了序列化深拷贝逻辑,一行代码搞定
序列化方式示例(需实现 Serializable):
try (ByteArrayInputStream bis = new ByteArrayInputStream(
new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(obj);
// 实际需完整流操作,此处简化示意
)) {
return (T) new ObjectInputStream(bis).readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
要注意的典型陷阱
深浅拷贝问题常在不经意间引发 bug:
- 数组字段:
int[]是引用类型,clone()对数组本身是浅拷贝(即新数组引用指向原数组内容),但基本类型数组元素会被复制;对象数组仍需手动深拷贝每个元素 - 不可变类(如
String、包装类)无需深拷贝:它们的“共享”是安全的 - 单例、线程局部变量、资源句柄(如
FileInputStream)不能也不应被拷贝,需在 clone 逻辑中显式排除或重置 - 循环引用:序列化方式能自动处理,但手动克隆容易陷入无限递归,需加缓存或标记
怎么选?看实际需求
多数业务场景下:
- 若只是临时隔离数据、避免副作用,且对象结构简单 → 优先考虑重写
clone()+ 手动处理关键引用 - 若对象嵌套深、变动频繁、开发效率优先 → 用
SerializationUtils.clone()或 JSON 方式更省心 - 若性能敏感(如高频拷贝)、对象结构固定 → 自定义构造器或 builder 模式按需复制更可控
不复杂但容易忽略:拷贝前想清楚——哪些字段真需要独立副本,哪些共享反而更合理。


















