【java开发系列】—— 深克隆和浅克隆

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

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

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

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

  首先看一下类图

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

  【浅克隆】

 1 public Object clone() {
 2         Husband husband = null;
 3         try{
 4             husband = (Husband)super.clone();
 5         }catch(CloneNotSupportedException e){
 6             e.printStackTrace();
 7         }finally{
 8             return husband;
 9         }
10     }

  【深克隆】

 1 public Object deepClone() throws IOException,ClassNotFoundException {
 2         //将对象写到流里
 3         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 4         ObjectOutputStream oos = new ObjectOutputStream(bos);
 5         oos.writeObject(this);
 6         //从流里读回来
 7         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
 8         ObjectInputStream ois = new ObjectInputStream(bis);
 9         return ois.readObject();
10     }

  【全部代码】

  1 package com.xingoo.clone;
  2
  3 import java.io.ByteArrayInputStream;
  4 import java.io.ByteArrayOutputStream;
  5 import java.io.IOException;
  6 import java.io.ObjectInputStream;
  7 import java.io.ObjectOutputStream;
  8 import java.io.Serializable;
  9 import java.util.Date;
 10
 11 class Wife implements Serializable{
 12     private String name;
 13     private Date birthday;
 14
 15     public Wife(){
 16         name = "芙蓉姐姐";
 17         birthday = new Date();
 18     }
 19     public Date getBirthday(){
 20         return birthday;
 21     }
 22
 23     public String getName() {
 24         return name;
 25     }
 26     public void setName(String name) {
 27         this.name = name;
 28     }
 29 }
 30 class Husband implements Cloneable,Serializable{
 31     private Wife wife;
 32     private Date birthday;
 33
 34     public Husband(){
 35         wife = new Wife();
 36         birthday = new Date();
 37     }
 38
 39     public Wife getWife(){
 40         return wife;
 41     }
 42
 43     public Date getBirthday(){
 44         return birthday;
 45     }
 46     /**
 47      * 浅克隆一个对象
 48      */
 49     public Object clone() {
 50         Husband husband = null;
 51         try{
 52             husband = (Husband)super.clone();
 53         }catch(CloneNotSupportedException e){
 54             e.printStackTrace();
 55         }finally{
 56             return husband;
 57         }
 58     }
 59     /**
 60      * 利用串行化深克隆一个对象,把对象以及它的引用读到流里,在写入其他的对象
 61      * @return
 62      * @throws IOException
 63      * @throws ClassNotFoundException
 64      */
 65     public Object deepClone() throws IOException,ClassNotFoundException {
 66         //将对象写到流里
 67         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 68         ObjectOutputStream oos = new ObjectOutputStream(bos);
 69         oos.writeObject(this);
 70         //从流里读回来
 71         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
 72         ObjectInputStream ois = new ObjectInputStream(bis);
 73         return ois.readObject();
 74     }
 75 }
 76 public class Test {
 77     public static void main(String[] args){
 78         try{
 79             Husband husband = new Husband();
 80             System.out.println("husband birthday "+husband.getBirthday().getTime());
 81             System.out.println("wife birthday "+husband.getWife().getBirthday().getTime());
 82             System.out.println();
 83             Husband husband1 = (Husband)husband.clone();
 84             System.out.println("husband1 birthday "+husband1.getBirthday().getTime());
 85             System.out.println("wife birthday "+husband1.getWife().getBirthday().getTime());
 86             System.out.println();
 87             System.out.println("是否是同一个husband "+(husband == husband1));
 88             System.out.println("是否是同一个wife "+ (husband.getWife() == husband1.getWife()));
 89             System.out.println();
 90             Husband husband2 = (Husband)husband.deepClone();
 91             System.out.println("husband2 birthday "+husband2.getBirthday().getTime());
 92             System.out.println("wife birthday "+husband2.getWife().getBirthday().getTime());
 93             System.out.println();
 94             System.out.println("是否是同一个husband "+(husband == husband2));
 95             System.out.println("是否是同一个wife "+ (husband.getWife() == husband2.getWife()));
 96         }catch(Exception e){
 97             e.printStackTrace();
 98         }
 99     }
100 }

  【运行结果】

husband birthday 1414247244668
wife birthday 1414247244668

husband1 birthday 1414247244668
wife birthday 1414247244668
是否是同一个husband false
是否是同一个wife true

husband2 birthday 1414247244668
wife birthday 1414247244668
是否是同一个husband false
是否是同一个wife false

 

本文转自博客园xingoo的博客,原文链接:【java开发系列】—— 深克隆和浅克隆,如需转载请自行联系原博主。

时间: 2024-10-24 09:16:38

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

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

原文:[java开发系列]-- struts2简单入门示例 上篇推荐:JDK安装 前言 最近正好有时间总结一下,过去的知识历程,虽说东西都是入门级的,高手肯定是不屑一顾了,但是对于初次涉猎的小白们,还是可以提供点参考的. struts2其实就是为我们封装了servlet,简化了jsp跳转的复杂操作,并且提供了易于编写的标签,可以快速开发view层的代码. 过去,我们用jsp和servlet搭配,实现展现时,答题的过程是: 1 jsp出发action 2 servlet接受action,交给后台c

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

由于之前Eclipse里面有一个可移植性的web工程,但是在我很久没用后,再次登录这个IDE的时候就发现了问题. 首先,我的电脑里面有两个版本的JDK,1.6和1.7.两个版本的Tomcat6和7以及两个版本的Eclipse IDE 3.5和4.0+. 当我启动开发环境后,想要向server中添加应用,发现报错: There are no resources that can be added or removed from the server. 我之前好用的应用怎么回不好使呢.于是删除ser

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

之前在开发中,就总纳闷,为什么继承接口时,会出现@Override注解,有时候还会提示写注解@SuppressWarnings? 原来这是java特有的特性,注解! 那么什么是注解呢? 注解就是某种注解类型的一个实例,我们可以用它在某个类上进行标注,这样编译器在编译我们的文件时,会根据我们自己设定的方法来编译类. 注解都是什么呢?看下面这张图就明白了! 上面的图可以看出,注解大体上分为三种:标记注解,一般注解,元注解 @Override用于标识,该方法是继承自超类的.这样,当超类的方法修改后,实

【java开发系列】—— JDOM创建、修改、删除、读取XML文件

有很多中操作XML文件的方法,这里介绍一下JDOM的使用方法和技巧. JDOM下载地址 创建XML文档 XML文件是一种典型的树形文件,每个文档元素都是一个document元素的子节点.而每个子元素都是一个Element对象,对象可以向下包含. 1 因此我们可以通过先创建元素再将元素添加到父元素中,最后将顶层元素添加到根元素中. 2 创建完文档元素后,就可以把元素添加到document对象中,然后写入文件. 主要使用的函数: Element.setAttribute 为元素添加信息 Elemen

【java开发系列】—— 集合使用方法

前言 在java中提供给我们了一些类似C++泛型的简单集合,list,set,map等.这里,简单介绍一下这些集合容器的使用方法,以及复杂对象元素的自定义排序. 首先看一下集合的框架图: 由于collection也继承了Iterator和comparable接口,因此我们可以使用Iterator来遍历元素,也可以通过自定义compareTo函数来重新编写自己的排序. List 1 package testCollection; 2 3 import java.util.ArrayList; 4

【java开发系列】—— java输入输出流

前言 任何语言输入输出流都是很重要的部分,比如从一个文件读入内容,进行分析,或者输出到另一个文件等等,都需要文件流的操作.这里简单介绍下reader,wirter,inputstream,outputstream的使用方法.其实Apache commons里面有个方法IOUtils可是实现方便快捷的流拷贝,感兴趣的可以参考官方文档. JAVA的输入输出流有两种,一种是字节流(InPutStream,OutPutStream),一种是字符流(Reader,Writer). 字节流是普遍适用的,比如

【java开发系列】—— 嵌套类与内部类

嵌套类与内部类在java中使用的很广泛,为了避免难以理解,这里用了几个小例子,说明它的用法. 嵌套类与内部类的结构如下图 静态嵌套类 静态嵌套类,是一种在类之外声明的嵌套类,由于是静态的,所以不经过初始化,就可以通过类名,直接调用. 1 class out1{ 2 private static String name = "xingoo"; 3 static class info{ 4 void print(){ 5 System.out.println("name:&quo

【java开发系列】—— struts2简单入门

前言 最近正好有时间总结一下,过去的知识历程,虽说东西都是入门级的,高手肯定是不屑一顾了,但是对于初次涉猎的小白们,还是可以提供点参考的. struts2其实就是为我们封装了servlet,简化了jsp跳转的复杂操作,并且提供了易于编写的标签,可以快速开发view层的代码. 过去,我们用jsp和servlet搭配,实现展现时,大体的过程是: 1 jsp触发action 2 servlet接受action,交给后台class处理 3 后台class跳转到其他的jsp,实现数据展现 现在有了stru

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

前言 作为一个java开发者,安装JDK是不可避免的,但是配置路径却总是记不住,百度也有很多参考例子.这里仅仅当做以后参考的笔记记录. 说到JDK,就不得不提JRE.他们到底是什么呢? 通常我们进行java开发,是要使用JDK的,它是专门给开发人员使用的API工具包,编译器,JRE等等.而JRE是java相关的应用程序运行时所需要的环境,所以相对于JDK来说,提供的东西要少一些. 比如,我们进行开发时,要去JDK的路径下寻找相应的jar包或者lib使用它其中的函数.而我们使用的eclipse本身