`

java对象 深度克隆(不实现Cloneable接口)和浅度克隆

阅读更多

详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt128

为什么需要克隆:

在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,AB是两个独立的对象,但B的初始值是由A对象确定的。在Java语言中,用简单的赋值语句是不能满足这种需求的,要满足这种需求有很多途径。

 

克隆的实现方式

一、浅度克隆

对于要克隆的对象,对于其基本数据类型的属性,复制一份给新产生的对象,对于非基本数据类型的属性,仅仅复制一份引用给新产生的对象,即新产生的对象和原始对象中的非基本数据类型的属性都指向的是同一个对象

1、实现java.lang.Cloneable接口

clone的类为什么还要实现Cloneable接口呢?Cloneable接口是一个标识接口,不包含任何方法的!这个标识仅仅是针对Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object clone()方法(也就是调用了super.Clone()方法),那么Objectclone()方法就会抛出 CloneNotSupportedException异常。

 

2、重写java.lang.Object.clone()方法

JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。

 

观察一下Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Objectclone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。Object类中的clone()还是一个protected属性的方法,重写之后要把clone()方法的属性设置为public

 

Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。

 

 

 

Java代码
  1. public class Product implements Cloneable {   
  2.     private String name;   
  3.   
  4.     public Object clone() {   
  5.         try {   
  6.             return super.clone();   
  7.         } catch (CloneNotSupportedException e) {   
  8.             return null;   
  9.         }   
  10.     }   
  11. }  

 

 

 

 

二、深度克隆

在浅度克隆的基础上,对于要克隆的对象中的非基本数据类型的属性对应的类,也实现克隆,这样对于非基本数据类型的属性,复制的不是一份引用,即新产生的对象和原始对象中的非基本数据类型的属性指向的不是同一个对象

 

要克隆的类和类中所有非基本数据类型的属性对应的类

1、都实现java.lang.Cloneable接口

 

2、都重写java.lang.Object.clone()方法

 

 

 

Java代码
  1. public class Attribute implements Cloneable {   
  2.     private String no;   
  3.        
  4.     public Object clone() {   
  5.         try {   
  6.             return super.clone();   
  7.         } catch (CloneNotSupportedException e) {   
  8.             return null;   
  9.         }   
  10.     }   
  11. }   
  12.   
  13. public class Product implements Cloneable {   
  14.     private String name;   
  15.        
  16.     private Attribute attribute;   
  17.   
  18.     public Object clone() {   
  19.         try {   
  20.             return super.clone();   
  21.         } catch (CloneNotSupportedException e) {   
  22.             return null;   
  23.         }   
  24.     }   
  25. }  

  

 

 

 

三、使用对象序列化和反序列化实现深度克隆

所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。

 

对象的序列化还有另一个容易被大家忽略的功能就是对象复制(Clone),Java中通过Clone机制可以复制大部分的对象,但是众所周知,Clone有深度Clone和浅度Clone,如果你的对象非常非常复杂,并且想实现深层 Clone,如果使用序列化,不会超过10行代码就可以解决。

 

虽然Java的序列化非常简单、强大,但是要用好,还有很多地方需要注意。比如曾经序列化了一个对象,可由于某种原因,该类做了一点点改动,然后重新被编译,那么这时反序列化刚才的对象,将会出现异常。 你可以通过添加serialVersionUID属性来解决这个问题。如果你的类是个单例(Singleton)类,是否允许用户通过序列化机制复制该类,如果不允许你需要谨慎对待该类的实现。

 

 

 

Java代码
  1. public class Attribute {   
  2.     private String no;   
  3. }   
  4.   
  5. public class Product {   
  6.     private String name;   
  7.        
  8.     private Attribute attribute;   
  9.   
  10.     public Product clone() {   
  11.         ByteArrayOutputStream byteOut = null;   
  12.         ObjectOutputStream objOut = null;   
  13.         ByteArrayInputStream byteIn = null;   
  14.         ObjectInputStream objIn = null;   
  15.            
  16.         try {   
  17.             byteOut = new ByteArrayOutputStream();    
  18.             objOut = new ObjectOutputStream(byteOut);    
  19.             objOut.writeObject(prototype);   
  20.   
  21.             byteIn = new ByteArrayInputStream(byteOut.toByteArray());   
  22.             objIn = new ObjectInputStream(byteIn);   
  23.                
  24.             return (ContretePrototype) objIn.readObject();   
  25.         } catch (IOException e) {   
  26.             throw new RuntimeException("Clone Object failed in IO.",e);      
  27.         } catch (ClassNotFoundException e) {   
  28.             throw new RuntimeException("Class not found.",e);      
  29.         } finally{   
  30.             try{   
  31.                 byteIn = null;   
  32.                 byteOut = null;   
  33.                 if(objOut != null) objOut.close();      
  34.                 if(objIn != null) objIn.close();      
  35.             }catch(IOException e){      
  36.             }      
  37.         }   
  38.     }   
分享到:
评论

相关推荐

    java克隆对象(两种方法)

    java的两种深度克隆方法,1cloneTest是用Cloneable接口的clone方法实现(对象必须要实现cloneable接口).2cloneSerialize.java是用对象流写对象到byte数组中,然后从byte数组中取得对象.(对象必须要实现serializble接口)

    详解Java中的克隆技术

    有关Java中的克隆技术的详细讲述,其中讲解了“浅复制”和“深复制”的用法和区别,继承了Java中的封装类Cloneable

    java设计模式【之】原型模式、深拷贝与浅拷贝【源码】【场景:克隆羊】

    * 需要被克隆的 class类, 重写Object中的clone()方法,并实现Cloneable接口(否则报错 CloneNotSupportedException) * 注意: * 1.被克隆对象.clone()出的对象,是被克隆对象的当前状态 * 2.被克隆对象 如果...

    【java系列文章】java 基础知识

    2.Java为什么不直接实现lterator接口,而是实现lterable? 3.简述什么是值传递和引用传递? 4.概括的解释下Java线程的几种可用状态? 中级 1.简述Java同步方法和同步代码块的区别 ? 2.HashMap和Hashtable有什么区别? 3....

    java编程常见问题

    当没有实现Cloneable接口或者不支持克隆方法时,调用其clone()方法则抛出该异常。 47.java.lang.EnumConstantNotPresentException 枚举常量不存在异常。当应用试图通过名称和枚举类型访问一个枚举对象,但该枚举对象...

    Test8.java

    该资源为Java源代码,设计了一个名为Complex的复数类,实现了复数运算的加减乘除和绝对值,覆盖了toString方法,实现了Cloneable接口。包含一个测试程序,提示用户输入两个复数,然后显示它们加减乘除之后的结果。

    Cloneable:使用C#Source Generator自动生成克隆方法

    安装可克隆您应该安装 : Install-Package Cloneable或者通过 .NET Core 命令行界面: dotnet add package Cloneable来自包管理器控制台或 .NET Core CLI 的任一命令都将下载并安装 Cloneable 和所有必需的依赖项。...

    java初学者必看

    最近正在学习Java,也买了很多的有关Java方面的书籍,其中发现《跟我学Java》这本书,都的很不错啊,所以顺便拿电脑把这本书的目录敲了下来,与大家分享。尤其是那些和我一样初学Java的朋友们,看看哪一节对你有用,...

    Java2游戏编程.pdf

    4.1.7 java.lang.Cloneable 4.1.8 java.lang.Thread 4.2 java.io包 4.3 java.util包 4.3.1 java.util.StringTokenizer 4.3.2 java.util.Random 4.3.3 Java2集合框架 4.4 总结 4.5 练习 第2篇 Java 2-D图像开发和抽象...

    Java集合面试题.docx

    为何 Collection 不从 Cloneable 和 Serializable 接口继承? 5. 为何 Map 接口不继承 Collection 接口? 6. Iterator 是什么? 7. Enumeration 和 Iterator 接口的区别? 8. 为何没有像 Iterator.add()这样的...

    java常用类解析及示例及一些工具类源代码

    主要讲解了System类、Object类、Arrays类、Cloneable接口、IO系统输入输出类及装饰类、IO系统文本读写工具类、IO系统二进制读写工具类、对象序列化工具类、File类及文件搜索工具类、java异常机制及自定义异常类、...

    GOF23之原型模式

    一、核心作用: ...实现Cloneable接口和重写clone()方法 四、示例: 一、浅克隆 实体类: package com.hezeu.prototype; import java.io.Serializable; import java.util.Date; /** *@Classname She

    java se和java ee基础功能点开发测试包

    该包围绕java se结合java ee的基础应用对目前最基础最常见的应用分别给以做了相关demo 具体包括有设计模式demo(设配模式、装饰模式、享元模式)、线程池设计方案、集合类容器demo、io流、Cloneable接口、自定义标签...

    06 类与对象31

    1.在类定义中实现Cloneable接口 2.在类中覆盖基类的clone()方法,声明为public,注意 4.使用clone方法时要进行强制转换 1.“浅克隆

    bigcoder84#study-notes#_4Object中的clone方法1

    Object类中的clone方法clone()方法的作用克隆方法用于创建对象的拷贝,为了使用clone方法,类必须实现java.lang.Cloneable接口

    JAVA高级程序设计测试题含答案.docx

    JAVA高级程序设计测试题含答案 JAVA高级...第14题 【单选题】【2.00分】【概念理解】 哪个方法是实现Runnable接口必须实现的 [单选题] * JAVA高级程序设计测试题含答案全文共43页,当前为第4页。 A. wait() B. run()

    java编程基础,应用与实例

    9.4 Cloneable 接口 143 9.5 Enumeration接口 144 9.6 巩固练习 145 第10章 内隐类(inner class) 146 10.1 静态类(static class) 146 10.2 成员类(member class) 147 10.3 局部类(local class) 150 ...

    Java程序设计复习题.docx.docx

    Java语言规定构造方法名与类名必须相同 Java语言规定构造方法没有返回值,但不用void声明 Java语言规定构造方法不可以重载 Java语言规定构造方法只能通过new自动调用 下列叙述中错误的是 D 。 Java Application与...

Global site tag (gtag.js) - Google Analytics