理解Java中的深拷贝和浅拷贝

下面列表是Java中深拷贝和浅拷贝的区别

Shallow CopyDeep Copy
Cloned Object and original object are not 100% disjoint. Cloned Object and original object are 100% disjoint.
Any changes made to cloned object will be reflected in original object or vice versa. Any changes made to cloned object will not be reflected in original object or vice versa.
Default version of clone method creates the shallow copy of an object. To create the deep copy of an object, you have to override clone method.
Shallow copy is preferred if an object has only primitive fields. Deep copy is preferred if an object has references to other objects as fields.
Shallow copy is fast and also less expensive. Deep copy is slow and very expensive.

表格来源Difference Between Shallow Copy Vs Deep Copy In Java

浅拷贝深拷贝
原对象和克隆对象并不是100%无关联 原对象和克隆对象100%无关联
对克隆对象的任何改变都会反映在原对象中,反之亦然 克隆对象的改变不会反映在原对象中,反之亦然
默认的clone()方法创建的是浅拷贝 要实现深拷贝,必须重写clone()方法
如果一个对象中字段只有基本类型,推荐浅拷贝 如果一个对象中字段存在其他对象的引用类型,推荐深拷贝
浅拷贝速度快,代价小 深拷贝相对较慢,代价大

通过实例理解浅拷贝和深拷贝TODO

作者:maxwellyue
链接:https://www.jianshu.com/p/beeba83fe503

 

在《Java编程思想》第16章数组部分,提到了System.arraycopy()对基本类型数组与对象数组的浅复制(参考P451),因此具体的来学习一下深拷贝与浅拷贝。

 

浅拷贝(Shallow Copy):

1. 对于基本数据类型,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。

2. 对于引用类型,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

 

深拷贝(deep copy):

1. 对于深拷贝来说,不仅要复制对象的所有基本数据类型,还要为所有引用类型的成员变量申请存储空间,并复制每个引用类型所引用的对象,直到该对象可达的所有对象。

 

(一)浅拷贝的实现方法

1. 引用赋值;

 

2. 重写clone方法:

Object类是类结构的根类,其中有一个进行浅拷贝的方法:

protected Object clone() throws CloneNotSupportedException

有了这个浅拷贝模板,我们可以通过调用clone()方法来实现对象的浅拷贝。但是需要注意:

i) Object类虽然有这个方法,但是这个方法是受保护的(被protected修饰),无法直接使用。因此使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException。

ii) 使用的基本形式:

复制代码
class A implements Cloneable {
    public Object clone() {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
        }
        return obj;
    }
}
复制代码
这一奇怪的用法《Java编程思想》的作者尝试给出了解释:Java刚开始作为一种驱动硬件的语言出现,那时候Object类有个方法是public Object clone();随着Java被用到网络编程中,clone方法的安全性受到质疑,因此设计者将public类型的clone方法修改为protected类型;但即便这样,仍然有安全问题,因为子类可能滥用父类的clone方法,因为它是protected类型的。为此,Java设计者又设计了一个Cloneable接口,当子类执行super.clone()语句时,会先核对执行该语句的子类对象是否实现了Cloneabe接口,以便确认开发者需要打开该子类的克隆功能,这就能最大程度的保证安全性。

 

(二)深拷贝的实习方法

1. 对每一个引用对象重写clone方法

与通过重写clone方法实现浅拷贝的基本思路一样,只需要为对象图的每一层的每一个对象都实现Cloneable接口并重写clone方法,最后在最顶层的类的重写的clone方法中调用所有的clone方法即可实现深拷贝。简单的说就是:每一层的每个对象都进行浅拷贝=深拷贝。

 

2. 通过对象序列化实现深拷贝(推荐使用)

将对象序列化为字节序列时,默认会将该对象的引用对象进行序列化,再通过反序列即可完美地实现深拷贝。

 

说明:所有内容仅做学习记录
posted @ 2019-07-28 12:47  xiaoshen666  阅读(190)  评论(0编辑  收藏  举报