java浅克隆和深克隆
来源:互联网 发布:手机淘宝客链接转换器 编辑:程序博客网 时间:2024/05/21 09:53
Java支持我们对一个对象进行克隆,通常用在装饰模式和原型模式中。那么什么是深克隆,什么是浅克隆呢。
【浅克隆】,通常只是对克隆的实例进行复制,但里面的其他子对象,都是共用的。【深克隆】,克隆的时候会复制它的子对象的引用,里面所有的变量和子对象都是又额外拷贝了一份。 也就是说,一个默认的clone()方法实现机制,仍然是赋值。如果一个被复制的属性都是基本类型,那么只需要实现当前类的cloneable机制就可以了,此为浅拷贝。如果被复制对象的属性包含其他实体类对象引用,那么这些实体类对象都需要实现cloneable接口并覆盖clone()方法。
下面的两个例子可以很好的说明他们的区别:
首先看一下类图
Husband类有一个对wife的引用,当进行浅克隆的时,wife变量都会指向同一个Wife;而进行深克隆时,会指向不同的Wife。下面进行一下验证:
java赋值
@Testpublic void testassign(){ Person p1=new Person(); p1.setAge(31); p1.setName("Peter"); Person p2=p1; System.out.println(p1==p2);//true}
如果创建一个对象的新的副本,也就是说他们的初始状态完全一样,但以后可以改变各自的状态,而互不影响,就需要用到java中对象的复制,如原生的clone()方法。
【浅克隆】
Object对象有个clone()方法,实现了对象中各个属性的复制,但它的可见范围是protected的,所以实体类使用克隆的前提是:
① 实现Cloneable接口,这是一个标记接口,自身没有方法。 ② 覆盖clone()方法,可见性提升为public。
public Object clone() { Husband husband = null; try{ husband = (Husband)super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); }finally{ return husband; } }
【深克隆】
public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(src); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(byteIn); List<T> dest = (List<T>) in.readObject(); return dest;}
【全部代码】
package entity;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;import java.util.Date;class Wife implements Serializable { private String name; private Date birthday; public Wife() { name = "芙蓉姐姐"; birthday = new Date(); } public Date getBirthday() { return birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; }}class Husband implements Cloneable, Serializable { private Wife wife; private Date birthday; public Husband() { wife = new Wife(); birthday = new Date(); } public Wife getWife() { return wife; } public Date getBirthday() { return birthday; } /** * 浅克隆一个对象 */ public Object clone() { Husband husband = null; try { husband = (Husband) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } finally { return husband; } } /** * 利用串行化深克隆一个对象,把对象以及它的引用读到流里,在写入其他的对象 * * @return * @throws IOException * @throws ClassNotFoundException */ public Object deepClone() throws IOException, ClassNotFoundException { // 将对象写到流里 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); // 从流里读回来 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); }}public class Test { public static void main(String[] args) { try { Husband husband = new Husband(); System.out.println("husband birthday " + husband.getBirthday().getTime()); System.out.println("wife birthday " + husband.getWife().getBirthday().getTime()); System.out.println(); Husband husband1 = (Husband) husband.clone(); System.out.println("husband1 birthday " + husband1.getBirthday().getTime()); System.out.println("wife birthday " + husband1.getWife().getBirthday().getTime()); System.out.println(); System.out.println("是否是同一个husband " + (husband == husband1)); System.out.println("是否是同一个wife " + (husband.getWife() == husband1.getWife())); System.out.println(); Husband husband2 = (Husband) husband.deepClone(); System.out.println("husband2 birthday " + husband2.getBirthday().getTime()); System.out.println("wife birthday " + husband2.getWife().getBirthday().getTime()); System.out.println(); System.out.println("是否是同一个husband " + (husband == husband2)); System.out.println("是否是同一个wife " + (husband.getWife() == husband2.getWife())); } catch (Exception e) { e.printStackTrace(); } }}
【运行结果】
husband birthday 1508228006939wife birthday 1508228006939husband1 birthday 1508228006939wife birthday 1508228006939是否是同一个husband false是否是同一个wife truehusband2 birthday 1508228006939wife birthday 1508228006939是否是同一个husband false是否是同一个wife false
【总结】
clone方式深拷贝
① 如果有一个非原生成员,如自定义对象的成员,那么就需要:该成员实现Cloneable接口并覆盖clone()方法,不要忘记提升为public可见。同时,修改被复制类的clone()方法,增加成员的克隆逻辑。② 如果被复制对象不是直接继承Object,中间还有其它继承层次,每一层super类都需要实现Cloneable接口并覆盖clone()方法。与对象成员不同,继承关系中的clone不需要被复制类的clone()做多余的工作。一句话来说,如果实现完整的深拷贝,需要被复制对象的继承链、引用链上的每一个对象都实现克隆机制。前面的实例还可以接受,如果有N个对象成员,有M层继承关系,就会很麻烦。
利用序列化实现深拷贝
clone机制不是强类型的限制,比如实现了Cloneable并没有强制继承链上的对象也实现;也没有强制要求覆盖clone()方法。因此编码过程中比较容易忽略其中一个环节,对于复杂的项目排查就是困难了。要寻找可靠的,简单的方法,序列化就是一种途径。被复制对象的继承链、引用链上的每一个对象都实现java.io.Serializable接口。这个比较简单,不需要实现任何方法,serialVersionID的要求不强制,对深拷贝来说没毛病。实现自己的deepClone方法,将this写入流,再读出来。俗称:冷冻-解冻。
原生的clone效率无疑是最高的,用脚趾头都能想到。 偶尔用一次,用哪个都问题都不大。 一般性能要求稍高的应用场景,cglib和orika完全可以接受。 另外一个考虑的因素,如果项目已经引入了某个依赖,就用那个依赖来做吧,没必要再引入一个第三方依赖。
阅读全文
1 0
- java深克隆和浅克隆
- java深克隆和浅克隆
- java 深克隆和浅克隆区别
- java中的深克隆和浅克隆
- Java的深克隆和浅克隆
- JAVA中的深克隆和浅克隆
- java 深克隆和浅克隆
- Java中的浅克隆和深克隆
- java浅克隆和深克隆
- 理解Java浅克隆和深克隆
- java的克隆(深克隆和浅克隆)
- java对象克隆(浅克隆和深克隆)
- java克隆之深克隆和浅克隆
- Java深克隆浅克隆
- java深克隆浅克隆
- Java浅克隆深克隆
- 浅克隆和深克隆
- 深克隆和浅克隆
- 利用python进行数据分析-pandas.concat/subplots/gropuby/pivot_table,多文件整合、聚合、分组,子图
- 记录改改直接拿来用的echarts force layout
- Android蓝牙-实现主动发起连接
- linux 路由表设置 之 route 指令详解
- 【转载】----浏览器跨域请求之credentials
- java浅克隆和深克隆
- CalendarNote的总结
- spring框架学习
- mac Memcached安装及基本命令
- JAVA Zookeeper(3)-- 查看注册信息命令
- 桥接模式和策略模式的区别和联系
- 生成二维码
- node 文件改名
- VScode搭建TypeScript开发环境