什么是深拷贝和浅拷贝?
面试回答¶
面试官: 什么是深拷贝和浅拷贝?它们有什么区别?
你:
简单说,浅拷贝只复制对象本身,对象内部引用的子对象不复制;深拷贝会递归复制所有引用的对象,直到最基本类型。
举个例子:一张借书卡,浅拷贝是复印了借书卡的卡面信息,但卡号还指向同一个图书馆账户;深拷贝是给你办了一张全新的卡,连背后关联的账户也复制了一份,互不影响。
区别核心:
-
浅拷贝后,新旧对象共享内部引用对象,一处修改互相影响。
-
深拷贝后,新旧对象完全独立,内部子对象也是独立的副本。
实现方式:
-
clone() 方法 默认的
Object.clone()是浅拷贝。要深拷贝需要重写clone(),递归克隆内部引用对象,并要求所有相关类都实现Cloneable接口,比较麻烦。 -
序列化反序列化 最省事的方式。把对象序列化成字节流,再从字节流反序列化出来,得到全新的对象图。但要求类实现
Serializable,而且性能较差。 -
手动拷贝构造或工厂方法 编写构造函数或静态方法,手动 new 出子对象并赋值。代码量最大,但最灵活,不依赖 Cloneable/Serializable,性能可控。
-
第三方工具 像 Apache Commons Lang 的
SerializationUtils.clone(),或通过 JSON 序列化(如 Gson、Jackson)中转一把,操作简单,但也是基于序列化,存在性能开销。
场景选择:
-
对象内部全是基本类型或不可变对象时,浅拷贝足够,比如复制一个配置对象。
-
对象内部有可变引用类型(如 List、Date、自定义对象),且拷贝后需要独立修改,则必须用深拷贝,比如复制一份表单数据做草稿保存。
-
高频调用的场景,建议用手动拷贝构造,避免序列化带来的额外性能压力。
最需要留意的点: 深拷贝一定要处理好循环引用,否则序列化或递归克隆容易栈溢出。另外,不可变对象(String、LocalDate、Integer)不需要深拷贝,直接共享引用是安全的。
