HoRain云--Java深拷贝与浅拷贝全解析
本文详细讲解了Java中对象拷贝的两种方式:浅拷贝与深拷贝。通过对比表格清晰展示了它们在核心区别、对象独立性、性能开销等方面的差异。文章提供了三种实现方法:利用Cloneable接口递归实现、通过序列化机制实现,以及使用复制构造方法实现,并分析了各种方法的适用场景与注意事项。最后强调了根据对象结构和性能需求选择合适的拷贝方式,特别指出对于不可变对象,浅拷贝也是安全的。文中还包含了完整的代码示例,帮

🎬 HoRain云小助手:个人主页
🔥 个人专栏: 《Linux 系列教程》《c语言教程》
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
专栏介绍
|
专栏名称 |
专栏介绍 |
|
本专栏主要撰写C干货内容和编程技巧,让大家从底层了解C,把更多的知识由抽象到简单通俗易懂。 |
|
|
本专栏主要是注重从底层来给大家一步步剖析网络协议的奥秘,一起解密网络协议在运行中协议的基本运行机制! |
|
|
全面深入解析 docker 容器,从基础到进阶,涵盖原理、操作、实践案例,助您精通 docker。 |
|
|
本专栏主要撰写Linux干货内容,从基础到进阶,知识由抽象到简单通俗易懂,帮你从新手小白到扫地僧。 |
|
|
本专栏着重撰写Python相关的干货内容与编程技巧,助力大家从底层去认识Python,将更多复杂的知识由抽象转化为简单易懂的内容。 |
|
|
本专栏主要是发布一些考试和练习题库(涵盖软考、HCIE、HRCE、CCNA等) |
目录

在Java中,实现对象的拷贝主要分为浅拷贝和深拷贝两种方式,它们的主要区别在于对对象内部引用类型字段的处理方式不同。下面是一个详细的对比表格,帮助你快速理解它们的核心差异。
|
特性 |
浅拷贝 (Shallow Copy) |
深拷贝 (Deep Copy) |
|---|---|---|
|
核心区别 |
复制对象本身,但对于引用类型字段,只复制其内存地址。 |
递归地复制对象及其所有引用类型字段指向的实际对象,直到所有依赖对象都被复制。 |
|
对象独立性 |
拷贝对象与原对象中的引用类型字段仍指向同一对象,修改会相互影响。 |
拷贝对象与原对象完全独立,互不影响。 |
|
性能与开销 |
创建速度快,内存开销小。 |
创建速度相对较慢,内存开销较大。 |
|
实现复杂度 |
简单。 |
复杂,需要递归处理所有引用对象。 |
💻 实现方式详解
实现浅拷贝
在Java中实现浅拷贝,主要依赖于让类实现 Cloneable接口并重写 Object类的 clone()方法。
-
实现
Cloneable接口:这是一个标记接口,用于告知JVM该类支持克隆。 -
重写
clone()方法:在方法内部调用super.clone()。Object类的clone()方法本身会实现按位复制,从而创建新对象。
class Person implements Cloneable {
private String name;
private Address address; // 引用类型字段
// ... 构造方法、getter、setter
@Override
protected Object clone() throws CloneNotSupportedException {
// 调用super.clone()实现浅拷贝
return super.clone();
}
}
在上例中,对 Person对象进行浅拷贝后,新 Person对象的 address字段和原对象指向的是同一个 Address对象。
实现深拷贝
实现深拷贝需要确保所有引用类型字段也被独立复制。以下是几种常见方法:
-
通过
clone()方法递归实现这是最直接的方式,但要求所有包含的引用类型字段对应的类也必须正确实现
Cloneable接口和clone()方法。class Address implements Cloneable { private String city; // ... 构造方法、getter、setter @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); // Address类自身的浅拷贝即可 } } class Person implements Cloneable { private String name; private Address address; // ... 构造方法、getter、setter @Override protected Object clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); // 关键步骤:对address字段也调用其clone方法,进行深拷贝 cloned.address = (Address) this.address.clone(); return cloned; } } -
通过序列化实现
如果对象图(所有相关联的对象)都实现了
java.io.Serializable接口,可以利用序列化机制轻松实现深拷贝。这种方式无需手动处理复杂的嵌套关系。import java.io.*; public class SerializationUtils { public static <T extends Serializable> T deepCopy(T obj) throws Exception { // 将对象写入字节流 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(obj); oos.close(); // 从字节流中读回新对象 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (T) ois.readObject(); } } // 使用:确保Person和Address都实现了Serializable接口 Person original = new Person("Alice", new Address("Beijing")); Person deepCopy = SerializationUtils.deepCopy(original);这种方法的优点是简单,但性能较低,且所有涉及的对象都必须可序列化。
-
通过复制构造方法或工厂方法
你也可以通过编写自定义的代码来逐一复制字段,例如为类添加一个接受自身类型参数的构造方法(复制构造方法)。
class Address { private String city; public Address(Address other) { this.city = other.city; // 对于String等不可变对象,直接赋值是安全的 } } class Person { private String name; private Address address; public Person(Person other) { this.name = other.name; this.address = new Address(other.address); // 为address创建新对象 } }
💡 如何选择与注意事项
-
性能与简单性:如果对性能要求高,且对象结构不复杂,优先选择通过
clone()递归实现。如果追求实现简单,且对象图都是可序列化的,序列化是不错的选择。 -
数组的拷贝:Java数组本身实现了
Cloneable接口,但Arrays.copyOf()和方法clone()对对象数组进行的是浅拷贝。如需深拷贝对象数组,需要遍历数组并对每个元素实施深拷贝。 -
不可变对象:如果类中包含的引用类型字段是不可变对象(如
String),由于它们无法被修改,使用浅拷贝也是安全的,因为不存在意外修改的风险。
希望这份详细的解释能帮助你彻底理解Java中的深拷贝与浅拷贝。如果你有特定的对象结构需要讨论,我可以提供更具体的实现建议。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙
更多推荐



所有评论(0)