java 克隆的浅拷贝与深拷贝
2015-09-01 12:16
711 查看
java中的克隆方法是clone();
当使用clone()方法去拷贝一个对象的时候,拷贝后的新对象与老对象是两个地址不同的对象
满足 :
老对象.clone() != 新对象
老对象.clone().getClass() == 新对象.geClass()
老对象.clone().equals(新对象) == true
但是 ,如果对象中成员变量包含对其他对象的引用的时候,用clone()方法克隆出来的新对象的引用同老对象的引用指向的是同一个对象,改变任何一个对象引用中的属性均对另一个产生影响。这就是clone()方法的浅拷贝
那么,如何将浅拷贝转换成深拷贝那,实现Cloneable接口,自己实现clone方法,并在clone方法中将对掐对象的引用也clone一份,这样克隆出来的新对象对其他对象的引用就同样拷贝了一份,实现了深层拷贝
同样,还可以利用串行化进行深拷贝
把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做 “解冻”或者“回鲜(depicking)”过程。
应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。
在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。
测试:
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型的变量是被包括进去的。
当使用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型的变量是被包括进去的。
相关文章推荐
- Cglib 与 JDK动态代理的运行性能比较
- jdk jre jvm三者之间的联系与区别
- Java IO
- Java容器类
- java gc的log分析
- java 读写锁 , 官方自带示例读解,ReentrantReadWriteLock
- 【leetcode】Excel Sheet Column Title【java】
- Eclipse 的git相关配置
- Eclipse Mars Release (4.5.0)下安装编译Spark2.7.1
- Spring笔记――3.容器中的Bean
- Spring Java Mail发邮件
- 深入浅出学Spring Data JPA
- Java反射的例子
- java中的数学计算函数
- Struts2的struts.xml中配置及通配符的使用
- Java泛型中的extends和super关键字
- java实现区域内屏幕截图示例
- 日记 - Think in java 之 对象导论 一
- Java导出Excel
- Java中两种实现多线程方式的对比分析