Java支持我们对一个对象进行克隆,通常用在装饰模式和原型模式中。那么什么是深克隆,什么是浅克隆呢。

  【浅克隆】,通常只是对克隆的实例进行复制,但里面的其他子对象,都是共用的。

  【深克隆】,克隆的时候会复制它的子对象的引用,里面所有的变量和子对象都是又额外拷贝了一份。

  下面的两个例子可以很好的说明他们的区别:

  首先看一下类图

  Husband类有一个对wife的引用,当进行浅克隆的时,wife变量都会指向同一个Wife;而进行深克隆时,会指向不同的Wife。下面进行一下验证:

  【浅克隆】

 public Object clone() {
Husband husband = null;
try{
husband = (Husband)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}finally{
return husband;
}
}

  【深克隆】

 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();
}

  【全部代码】

 package com.xingoo.clone;

 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
wife birthday husband1 birthday
wife birthday
是否是同一个husband false
是否是同一个wife true husband2 birthday
wife birthday
是否是同一个husband false
是否是同一个wife false

【java开发系列】—— 深克隆和浅克隆的更多相关文章

  1. Java中的深克隆和浅克隆

    为什么要克隆 首先思考一个问题, 为什么需要克隆对象? 直接new一个对象不行吗? 克隆的对象可能包含一些已经修改过的属性, 而new出来的对象的属性都还是初始化时候的值, 所以当需要一个新的对象来保 ...

  2. 浅谈Java中的深克隆和浅克隆(阿里面试)

    在最近的秋招中,阿里和多益网络都问到了这个问题,虽然很简单,但是我还是想总结一下,感兴趣的可以看一下我的个人博客网站(Spring+MyBatis+redis+nginx+mysql)(适合菜鸟),最 ...

  3. 【java开发系列】—— JDK安装

    前言 作为一个java开发者,安装JDK是不可避免的,但是配置路径却总是记不住,百度也有很多参考例子.这里仅仅当做以后参考的笔记记录. 说到JDK,就不得不提JRE.他们到底是什么呢? 通常我们进行j ...

  4. Java开发系列-文件上传

    概述 Java开发中文件上传的方式有很多,常见的有servlet3.0.common-fileUpload.框架.不管哪种方式,对于文件上传的本质是不变的. 文件上传的准备 文件上传需要客户端跟服务都 ...

  5. 【java开发系列】—— struts2简单入门示例

    前言 最近正好有时间总结一下,过去的知识历程,虽说东西都是入门级的,高手肯定是不屑一顾了,但是对于初次涉猎的小白们,还是可以提供点参考的. struts2其实就是为我们封装了servlet,简化了js ...

  6. 【java开发系列】—— 自定义注解

    之前在开发中,就总纳闷,为什么继承接口时,会出现@Override注解,有时候还会提示写注解@SuppressWarnings? 原来这是java特有的特性,注解! 那么什么是注解呢? 注解就是某种注 ...

  7. 【java开发系列】—— Tomcat编译报错

    由于之前Eclipse里面有一个可移植性的web工程,但是在我很久没用后,再次登录这个IDE的时候就发现了问题. 首先,我的电脑里面有两个版本的JDK,1.6和1.7.两个版本的Tomcat6和7以及 ...

  8. Java开发系列-JSP

    概述 JSP是java 服务器页面,它运行在服务器端,本质上就是一个serlvet,产生的java文件和class保留在tomcat的word目录下. JSP主要作用是将内容的生成与页面相分离. JS ...

  9. Java开发系列-JDBC

    概述 JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和 ...

随机推荐

  1. HDU6470 ()矩阵快速幂

    http://acm.hdu.edu.cn/showproblem.php?pid=6470 题意:f[n] = f[n-1] + f[n-2]*2 + n^3; f[1] =1 ; f[2] = 2 ...

  2. DFS/BFS视频讲解

    视频链接:https://www.bilibili.com/video/av12019553?share_medium=android&share_source=qq&bbid=XZ7 ...

  3. python学习8-闭包、迭代器(转载)

    一.第一类对象: 函数名是一个变量,可以当普通变量使用,但它又是一个特殊的变量,与括号配合可以执行函数. 函数名的运用 1.单独打印是一个内存地址 2.可以给其他变量赋值 3.可以作为容器类变量的元素 ...

  4. nginx 模块介绍

    nginx模块在编译文件下的odjs目录下 cat 查看ngx_modules.c文件 可以看到一些基本extern模块 常用标准模块 1. 性能相关配置 worker_processes numbe ...

  5. 关于i18n

    现在工作主要负责小程序端,很少负责backend.最近的一个任务是配置多语言.因为一开始都是写死的中文,现在需要把那些变成英文. 狂搜了一波,其实网上的方法都不怎好.(可能就是一开始看的时候觉得好.) ...

  6. 使用urllib和http.cookiejar获取python老男孩学员成绩

    打开http://crm.oldboyedu.com/crm/grade/single/ 鼠标右键查看源代码,可以看到我们需要post的name.如下: 这里需要在post试提交token和searc ...

  7. angular的基本要点

    <body ng-app="Myapp"> <div ng-controller="firstcon"> <h1>hello ...

  8. Thinking in java源码下载链接

    Thinking in java书上显示的下载源码到www.mindview.net站点,但是这个站点打不开了,后来找到真正的下载地址,贴于此. http://www.mindviewinc.com/ ...

  9. 移除“xmlns”命名空间

    用XmlDocument创建一个文档,或者插入一个节点,默认会生成xmlns(命名空间)特性. 假定有一个xml文档如下结构: <?xml version="1.0" enc ...

  10. unity手游使用terrian注意事项

    1.Terrain比较占性能,普通机器测试,未开terrain  60帧,开启terrain后  30帧 2.Terrain的size大小与占用性能无关,不过越小的Terrain的烘焙上去的阴影越模糊 ...