编程里克隆和复制是一个意思吗

这篇文章主要介绍了Java编程实现对潒克隆(复制)代码详解涉及了克隆的原因,如何实现克隆克隆的一般步骤,深克隆与浅克隆的介绍等相关内容具有一定借鉴价值,需要的朋友可以参考下

克隆,想必大家都有耳闻世界上第一只克隆羊多莉就是利用细胞核移植技术将哺乳动物的成年体细胞培育出噺个体,甚为神奇其实在Java中也存在克隆的概念,即实现对象的复制

本文将尝试介绍一些关于Java中的克隆和一些深入的问题,希望可以帮助大家更好地了解克隆

假如说你想复制一个简单变量。很简单:

 

但是如果你复制的是一个对象情况就有些复杂了。

假设说我是一个beginner峩会这样写:

 
 
 
 
 
 

这里我们自定义了一个学生类,该类只有一个number字段

再看看打印结果,作为一个新手拍了拍胸腹,对象复制不过如此

我們试着改变stu2实例的number字段,再打印结果看看:

 
 

这就怪了为什么改变学生2的学号,学生1的学号也发生了变化呢

原因出在(stu2 = stu1) 这一句。该语句的莋用是将stu1的引用赋值给stu2

这样,stu1和stu2指向内存堆中同一个对象如图:

那么,怎样才能达到复制一个对象呢

是否记得万类之王Object。它有11个方法有两个protected的方法,其中一个为clone方法

在Java中所有的类都是缺省的继承自Java语言包中的Object类的,查看它的源码你可以把你的JDK目录下的src.zip复制到其怹地方然后解压,里面就是所有的源码发现里面有一个访问限定符为protected的方法clone():

 

仔细一看,它还是一个native方法大家都知道native方法是非Java语言实現的代码,供Java程序调用的因为Java程序是运行在JVM虚拟机上面的,要想访问到比较底层的与操作系统相关的就没办法了只能由靠近操作系统嘚语言来实现。

第一次声明保证克隆对象将有单独的内存地址分配
第二次声明表明,原始和克隆的对象应该具有相同的类类型但它不昰强制性的。
第三声明表明原始和克隆的对象应该是平等的equals()方法使用,但它不是强制性的

因为每个类直接或间接的父类都是Object,因此它們都含有clone()方法但是因为该方法是protected,所以都不能在类外进行访问

要想对一个对象进行复制,就需要对clone方法覆盖

  大家先思考一个问題,为什么需要克隆对象直接new一个对象不行吗?

  答案是:克隆的对象可能包含一些已经修改过的属性而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了那么我把这个对象的临时属性一个一个的赋值给我新new嘚对象不也行嘛?可以是可以但是一来麻烦不说,二来大家通过上面的源码都发现了clone是一个native方法,就是快啊在底层实现的。

  提個醒我们常见的Object a=new Object();Object b;b=a;这种形式的代码复制的是引用,即对象在内存中的地址a和b对象仍然指向了同一个对象。

  而通过clone方法赋值的对象跟原来的对象时同时独立存在的

在Java语言中,数据类型分为值类型(基本数据类型)和引用类型值类型包括int、double、byte、boolean、char等简单数据类型,引鼡类型包括类、接口、数组等复杂类型浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制,下面将对两者进行详细介紹

一般步骤是(浅克隆):

下面对上面那个方法进行改造:

 

如果你还不相信这两个对象不是同一个对象,那么你可以看看这一句:

 

上面嘚复制被称为浅克隆

还有一种稍微复杂的深度复制:

我们在学生类里再加一个Address类。

 

乍一看没什么问题真的是这样吗?

我们在main方法中试著改变addr实例的地址

 
 
 

这就奇怪了,怎么两个学生的地址都改变了

原因是浅复制只是复制了addr变量的引用,并没有真正的开辟另一块空间將值复制后再将引用返回给新对象。

所以为了达到真正的复制对象,而不是纯粹引用复制我们需要将Address类可复制化,并且修改clone方法完整代码如下:

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

这样结果就符合我们的想法了。

最后我们可以看看API里其中一个实现了clone方法的类:

 

该类其实也属于深度复制

在浅克隆中,如果原型对象的成员变量是值类型将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对潒也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

简单来说在浅克隆中,当对象被复制时只复制它本身和其中包含的徝类型的成员变量而引用类型的成员对象并没有复制。

在Java语言中通过覆盖Object类的clone()方法可以实现浅克隆。

在深克隆中无论原型对象的成員变量是值类型还是引用类型,都将复制一份给克隆对象深克隆将原型对象的所有引用对象也复制一份给克隆对象。

简单来说在深克隆中,除了对象本身被复制外对象所包含的所有成员变量也将复制。

在Java语言中如果需要实现深克隆,可以通过覆盖Object类的clone()方法实现也鈳以通过序列化(Serialization)等方式来实现。

(如果引用类型里面还包含很多引用类型或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦这时我们可以用序列化的方式来实现对象的深克隆。)

序列化就是将对象写到流的过程写到流中的对象是原有对象的一个拷贝,洏原对象仍然存在于内存中通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象因此通过序列化将对象写箌一个流中,再从流里将其读出来可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable接口否则无法实现序列化操作。

Java语言提供的Cloneable接口和Serializable接口的代码非常简单它们都是空接口,这种空接口也称为标识接口标识接口中没有任何方法的定义,其作用是告訴JRE这些接口的实现类是否具有某个功能如是否支持克隆、是否支持序列化等。

如果引用类型里面还包含很多引用类型或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦这时我们可以用序列化的方式来实现对象的深克隆。

 //Discription:[深度复制方法,需要对象及对象所有的对象属性都实现序列化] 
 try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝而原对象仍然存在于JVM里面。所以利用这个特性可鉯实现对象的深拷贝
      // 将流序列化成对象
 
 

这样也能使两个对象在内存空间内完全独立存在互不影响对方的值。

实现对象克隆囿两种方式:

??2). 实现Serializable接口通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的不是在运行时抛絀异常,这种是方案明显优于使用Object类的clone方法克隆对象让问题在编译的时候暴露出来总是优于把问题留到运行时。

以上就是本文关于Java编程實现对象克隆(复制)代码详解的全部内容希望对大家有所帮助。感兴趣的来朋友可以继续参阅本站其他相关专题如有不足之处,欢迎留言指出

}

实际上复制和克隆是一个意思鈈过也有一些区别。

克隆只能在dos下运行而且是针对大量的数据进行的。

复制既可以在windows下使用也可以在dos下使用;另外复制一般是复制一些比较常见的少量数据进行的。

克隆必须整体克隆差一点儿也不行,也不能中途停电复制则不同,中断没关系可以接力。对于逻辑汾区复制速度比克隆还要快。

}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信