您的位置:首页 > 编程语言 > Java开发

java 克隆的浅拷贝与深拷贝

2015-09-01 12:16 711 查看
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型的变量是被包括进去的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: