java 克隆的浅拷贝与深拷贝

来源:互联网 发布:济南淘宝代运营公司 编辑:程序博客网 时间:2024/05/22 09:45

java中的克隆方法是clone();

当使用clone()方法去拷贝一个对象的时候,拷贝后的新对象与老对象是两个地址不同的对象

满足 :

老对象.clone() != 新对象

老对象.clone().getClass() == 新对象.geClass()

老对象.clone().equals(新对象) == true

但是 ,如果对象中成员变量包含对其他对象的引用的时候,用clone()方法克隆出来的新对象的引用同老对象的引用指向的是同一个对象,改变任何一个对象引用中的属性均对另一个产生影响。这就是clone()方法的浅拷贝

那么,如何将浅拷贝转换成深拷贝那,实现Cloneable接口,自己实现clone方法,并在clone方法中将对掐对象的引用也clone一份,这样克隆出来的新对象对其他对象的引用就同样拷贝了一份,实现了深层拷贝

<span style="font-size:18px;">public Object clone(){Student o = null;try {o = (Student)super.clone();o.p = (Person) p.clone(); //将引用也克隆一份} catch (CloneNotSupportedException e) {e.printStackTrace();}return o;}</span>

同样,还可以利用串行化进行深拷贝

把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做 “解冻”或者“回鲜(depicking)”过程。 
    应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。 
    在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。 

public Object deepClone(){ByteArrayOutputStream bos; ObjectOutputStream oos;ByteArrayInputStream bis;ObjectInputStream ois;Object o =null;try {//将对象写到流中bos= new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);oos.writeObject(this);//将流中的对象读出bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);o= ois.readObject();} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}return o;}//前提是此类和成员变量对象的应用实现Serializable接口

测试:

public static void main(String[] args) {Person p = new Person("王小二", 22, "北京市");Student s1 = new Student("小明", 12, p);Student s2 =(Student) s1.deepClone();//(Student) s1.clone();System.out.println("s1对象"+s1);System.out.println("s2对象"+s2);System.out.println("s1对象年龄:"+s1.age+"  s1对象名字:"+s1.name+"  s1对象的引用对象Person:"+s1.p);System.out.println("s2对象年龄:"+s2.age+"  s2对象名字:"+s2.name+"  s2对象的引用对象Person:"+s2.p);}
测试结果

s1对象com.isoftstone.Student@d3db51
s2对象com.isoftstone.Student@bad8a8
s1对象年龄:12  s1对象名字:小明  s1对象的引用对象Person:com.isoftstone.Person@888e6c
s2对象年龄:12  s2对象名字:小明  s2对象的引用对象Person:com.isoftstone.Person@e61fd1

如果将引用的成员变量对象加上transient去修饰,再调用deepClone()方法,引用对象就不会拷贝

测试结果

s1对象com.isoftstone.Student@17494c8
s2对象com.isoftstone.Student@e020c9
s1对象年龄:12  s1对象名字:小明  s1对象的引用对象Person:com.isoftstone.Person@888e6c
s2对象年龄:12  s2对象名字:小明  s2对象的引用对象Person:null

transient解释:(by:百度百科)

Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。

0 0
原创粉丝点击