java 深浅copy
Posted llljjc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 深浅copy相关的知识,希望对你有一定的参考价值。
1.深浅copy的定义
1.浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制。
2.深拷贝:对象,对象内部的引用均复制。
1.1浅拷贝图示
为了更好的理解它们的区别我们假设有一个对象A,它包含有2对象对象A1和对象A2,如图:
对象A进行浅拷贝后,得到对象B但是对象A1和A2并没有被拷贝,如图:
1.2深拷贝图示
对象A进行深拷贝,得到对象B的同时A1和A2连同它们的引用也被拷贝,如图:
1.3Java的clone()方法
1.clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
(1)对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象 。
(2)对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样 。
(3)如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。
2.Java中对象的克隆 :
(1)为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
(2)在派生类中覆盖基类的clone()方法,并声明为public。
(3)在派生类的clone()方法中,调用super.clone()。
(4)在派生类中实现Cloneable接口。
2.浅拷贝
2.1浅拷贝分类
1.对于数据类型是基本数据类型的成员变量:
浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。
2.对于数据类型是引用数据类型的成员变量:
比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
2.2浅拷贝实现方式
1.通过拷贝构造方法实现浅拷贝:
拷贝构造方法指的是该类的构造方法参数为该类的对象。使用拷贝构造方法可以很好地完成浅拷贝,直接通过一个现有的对象创建出与该对象属性相同的新的对象。
注意:如果在拷贝构造方法中,对引用数据类型变量逐一开辟新的内存空间,创建新的对象,也可以实现深拷贝。而对于一般的拷贝构造,则一定是浅拷贝。
2.通过重写clone()方法进行浅拷贝:
Object类是类结构的根类,其中有一个方法为protected Object clone() throws CloneNotSupportedException,这个方法就是进行的浅拷贝。有了这个浅拷贝模板,我们可以通过调用clone()方法来实现对象的浅拷贝。但是需要注意:(1)、Object类虽然有这个方法,但是这个方法是受保护的(被protected修饰),所以我们无法直接使用。(2)、使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException。对于这两点,我们的解决方法是,在要使用clone方法的类中重写clone()方法,通过super.clone()调用Object类中的原clone方法。
3.深拷贝
3.1深拷贝的实现方式:
1.通过重写clone方法来实现深拷贝:
与通过重写clone方法实现浅拷贝的基本思路一样,只需要为对象图的每一层的每一个对象都实现Cloneable接口并重写clone方法,最后在最顶层的类的重写的clone方法中调用所有的clone方法即可实现深拷贝。简单的说就是:每一层的每个对象都进行浅拷贝=深拷贝。
2.通过对象序列化实现深拷贝:
虽然层次调用clone方法可以实现深拷贝,但是显然代码量实在太大。特别对于属性数量比较多、层次比较深的类而言,每个类都要重写clone方法太过繁琐。
-
被复制对象的继承链、引用链上的每一个对象都实现java.io.Serializable接口。这个比较简单,不需要实现任何方法,serialVersionID的要求不强制,对深拷贝来说没毛病。
-
实现自己的deepClone方法,将this写入流,再读出来。
1 public Object deepClone() throws Exception 2 { 3 // 序列化 4 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 5 ObjectOutputStream oos = new ObjectOutputStream(bos); 6 7 oos.writeObject(this); 8 9 // 反序列化 10 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 11 ObjectInputStream ois = new ObjectInputStream(bis); 12 13 return ois.readObject(); 14 }
以上是关于java 深浅copy的主要内容,如果未能解决你的问题,请参考以下文章