Java 基础之克隆 clone

September 4, 2014

Java

先说数据类型。Java 世界里,数据类型分两种,一种是基本数据类型,一种是引用类型。基础数据类型有8种,int,short,byte,long,char,boolean,float,double,当运行 int a = 1; 时,a 存放的是 1 这个值。引用类型,Java 世界里没有指针但是有引用,reference,当执行 Object obj = new Object() 时,obj 存放的是一个内存地址,在其他语言里,被称为指针,在 Java 里被称为对象引用。其实虚拟机里存放的就是一个和int 长度一样的 reference , 也就是内存地址。

浅克隆 shallow Clone

浅克隆也叫影子克隆,我觉得影子克隆会更好理解一些,而且人家本来就是叫影子克隆的,不知道为什么很多人喜欢叫它浅克隆,可能是为了和深克隆对应上吧。当一个类继承了 Clonable 后,就可以调用这个类的 clone() 方法。不继承而调用clone() 方法会抛一个异常CloneNotSupportedException。默认的,没有重写clone() 方法的话,ClassA b = a.clone() 只是简单的把对象 a 的内存内容复制到另外一个内存区域,并且把新克隆的内存地址赋给 b 。如果 ClassA 包含的都是基础数据类型的话,克隆后,a 和 b 没有任何的关系了,修改 a 不会影响到 b 。但是如果 ClassA 里有一个引用类型,那么克隆的时候,这个被引用的对象没有被克隆,克隆只是这个引用对象的地址,这样子的话,a 和 b 都引用同一个对象。修改 a 里的这个对象,就会影响到 b,b 里的这个对象也跟着被修改了。这个时候就需要深克隆 Deep clone 。

深克隆 Deep Clone

深克隆就是针对引用对象的克隆,不再只是简单的拷贝内存地址了。需要重写clone() 方法,并且需要调用 super.clone() 方法,也就是调用 Object 类的 clone() 方法。如果ClassA 里包含一个 ClassB 的引用 b,clone 的时候需要调用b.clone() , 而且ClassB 也是继承了Clonable 。如果非常不幸这个 ClassB 不是你写的,你也不能修改,那么你可以重新 new 一个 ClassB ,把需要的变量重新赋值一次。

深克隆还是浅克隆

使用深克隆还是使用浅克隆,具体看需求,深克隆也不是所有引用对象都要实现深克隆,只实现必须的行了。

对于初学者可能不好理解这个,或者会很生硬,建议可以看看Java虚拟机规范或者其他介绍Java虚拟机的书或文章后,再回来看这个,非常好理解。

通过 new 的方式重新实例化一个对象,然后把原对象的值依次赋值给新的对象,这样也可以实现克隆。但是这样的消耗会稍微大一些。b = a.clone(),是把当前对象 a 的内存内容拷贝一份,这样就包含了对象 a 的当前所有变量的状态。而如果通过重新 new 的话,虚拟机需要重新开辟一个内存,然后初始化对象,然后再从对象 a 里取出对应的变量值,赋给 b。从效率上要低了一些。

Java 专题整理

--- EOF ---

添加新评论