由Object类定义的绝大部分方法在本书其他部分讨论。而一个特别值得关注的方法是clone( )。clone( )方法创建调用它的对象的一个复制副本。只有那些实现Cloneable接口的类能被复制。
  
  Cloneable接口没有定义成员。它通常用于指明被创建的一个允许对对象进行位复制(也就是对象副本)的类。如果试图用一个不支持Cloneable接口的类调用clone(
)方法,将引发一个CloneNotSupportedExcepti

on异常。当一个副本被创建时,并没有调用被复制对象的构造函数。副本仅仅是原对象的一个简单精确的拷贝。

  
  复制是一个具有潜在危险的操作,因为它可能引起不是你所期望的副作用。例如,假如被复制的对象包含了一个称为obRef的引用变量,当副本创建时,副
本中的obRef如同原对象中的obRef一样引用相同的对象。如果副本改变了被obRef引用的对象的内容,那么对应的原对象也将被改变。这里是另一个
例子。如果一个对象打开一个I/O流并被复制,两个对象将可操作相同的流。而且,如果其中一个对象关闭了流,而另一个对象仍试图对I/O流进行写操作的
话,将导致错误。

  
  由于复制可能引起问题,因此在Object内,clone(
)方法被说明为protected。这就意味着它必须或者被由实现Cloneable的类所定义的方法调用,或者必须被那些类显式重载以便它是公共的。让我们看关于下面每一种方法的例子。

  
  下面的程序实现Cloneable接口并定义cloneTest( )方法,该方法在Object中调用clone(
)方法:
  
  // Demonstrate the clone() method.
  
  class TestClone implements Cloneable {
  
  int a;
  
  double b;
  
  // This method calls Object's clone().
  
  TestClone cloneTest() {
  
  try {
  
  // call clone in Object.
  
  return (TestClone) super.clone();
  
  } catch(CloneNotSupportedException e) {
  
  System.out.println("Cloning not allowed.");
  
  return this;
  
  }
  
  }
  
  }
  
  class CloneDemo {
  
  public static void main(String args[]) {
  
  TestClone x1 = new TestClone();
  
  TestClone x2;
  
  x1.a = 10;
  
  x1.b = 20.98;
  
  x2 = x1.cloneTest(); // clone x1
  
  System.out.println("x1: " + x1.a + " " + x1.b);
  
  System.out.println("x2: " + x2.a + " " + x2.b);
  
  }
  
  }
  
  这里,方法cloneTest( )在Object中调用clone( )方法并且返回结果。注意由clone(
)方法返回的对象必须被强制转换成它的适当类型(TestClone)。
  
  下面的例子重载clone(
)方法以便它能被其类外的程序所调用。为了完成这项功能,它的存取说明符必须是public,如下所示:
  
  // Override the clone() method.
  
  class TestClone implements Cloneable {
  
  int a;
  
  double b;
  
  // clone() is now overridden and is public.
  
  public Object clone() {
  
  try {
  
  // call clone in Object.
  
  return super.clone();
  
  } catch(CloneNotSupportedException e) {
  
  System.out.println("Cloning not allowed.");
  
  return this;
  
  }
  
  }
  
  }
  
  class CloneDemo2 {
  
  public static void main(String args[]) {
  
  TestClone x1 = new TestClone();
  
  TestClone x2;
  
  x1.a = 10;
  
  x1.b = 20.98;
  
  // here, clone() is called directly.
  
  x2 = (TestClone) x1.clone();
  
  System.out.println("x1: " + x1.a + " " + x1.b);
  
  System.out.println("x2: " + x2.a + " " + x2.b);
  
  }
  
  }
  
  由复制带来的副作用最初一般是比较难发现的。通常很容易想到的是类在复制时是很安全的,而实际却不是这样。一般在没有一个必须的原因的情况下,对任何类都不应该执行Cloneable。

浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念:

深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

此处,写一个深浅复制的例子:

public class Prototype implements Cloneable, Serializable {

  • private static final long serialVersionUID = 1L;
  • private String string;
  • private SerializableObject obj;
  • /* 浅复制 */
  • public Object clone() throws CloneNotSupportedException {
  • Prototype proto = (Prototype) super.clone();
  • return proto;
  • }
  • /* 深复制 */
  • 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 String getString() {
  • return string;
  • }
  • public void setString(String string) {
  • this.string = string;
  • }
  • public SerializableObject getObj() {
  • return obj;
  • }
  • public void setObj(SerializableObject obj) {
  • this.obj = obj;
  • }
  • }
  • class SerializableObject implements Serializable {
  • private static final long serialVersionUID = 1L;
  • }
 
要实现深复制,需要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。

使用clone( )和Cloneable接口的更多相关文章

  1. Cloneable接口和Object的clone()方法

    为什么要克隆 为什么要使用克隆,这其实反映的是一个很现实的问题,假如我们有一个对象: public class SimpleObject implements Cloneable { private ...

  2. Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨

    Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...

  3. (转)Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨

    原文地址:http://blog.csdn.net/kenthong/article/details/5758884 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的 ...

  4. java开发——Cloneable接口、clone()方法和深浅拷贝

    1.实现Cloneable接口表明该类的对象是允许克隆的. 2.允许克隆的意思是:可以调用clone()方法. 3.深拷贝还是浅拷贝,取决于如何重写Object的clone()方法. 4.原对象和克隆 ...

  5. Java 深拷贝、浅拷贝及Cloneable接口

    Cloneable接口是一个空接口,仅用于标记对象,Cloneable接口里面是没有clone()方法,的clone()方法是Object类里面的方法!默认实现是一个Native方法 protecte ...

  6. java 的对象拷贝(有深浅拷贝两种方式,深拷贝实现的两种方式(逐层实现cloneable接口,序列化的方式来实现))

    Java提高篇--对象克隆(复制)(转自:http://www.cnblogs.com/Qian123/p/5710533.html#_label0)   阅读目录 为什么要克隆? 如何实现克隆 浅克 ...

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

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt128 为什么需要克隆: 在实际编程过程中,我们常常要遇到这种情况:有一个对象 ...

  8. Java中的Cloneable接口理解

    Cloneable接口是一个标记接口,也就是没有任何内容,定义如下: 这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类 ...

  9. java Comparable 和 Cloneable接口

    Comparable接口定义了compareTo方法,用于比较对象. 例如,在JavaAPI中,Integer.BigInteger.String以及Date类定义如下 Cloneable接口 Clo ...

随机推荐

  1. art-template引擎模板

    art-template简介 artTemplate(后文简称aT)才是模板引擎,而TmodJS(后文简称TJ,曾用名atc)则是依赖于前者的一款模板预编译器.两者都是由腾讯开发.其实aT完全可以独立 ...

  2. CSS布局——横向两列布局

    1.固定两栏布局,使用float,注意对紧邻元素清除浮动影响.IE6在使用float布局同时设置横行margin的情况下会有双边距BUG,解决方案是加入_display:inline 代码如下: &l ...

  3. 收集oracle统计信息

    优化器统计范围: 表统计: --行数,块数,行平均长度:all_tables:NUM_ROWS,BLOCKS,AVG_ROW_LEN:列统计: --列中唯一值的数量(NDV),NULL值的数量,数据分 ...

  4. 编译hadoop eclipse的插件(hadoop1.0)

    原创文章,转载请注明: 转载自工学1号馆 欢迎关注我的个人博客:www.wuyudong.com, 更多云计算与大数据的精彩文章 在hadoop-1.0中,不像0.20.2版本,有现成的eclipse ...

  5. HDFS主要特性和体系结构

    引言 Hadoop分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统.它和现有的分布式文件系统有很多共同点.但同时,它和其他的分布式文件系统 ...

  6. Retrofit源码设计模式解析(上)

    Retrofit通过注解的方法标记HTTP请求参数,支持常用HTTP方法,统一返回值解析,支持异步/同步的请求方式,将HTTP请求对象化,参数化.真正执行网络访问的是Okhttp,Okhttp支持HT ...

  7. Mac平台下启动MySQL到完全终止MySQL----终端八步走

    1.选中Finder的情况下,快捷键进入搜索目录:/usr/local 然后进入mysql目录下: 2.右键 "从这里启动" 打开终端: 3.输入执行:./scripts/mysq ...

  8. OOD沉思录 --- 类和对象的关系 --- 包含关系1

    4.5 如果类包含另一个类的对象,那么包含类应当向被包含的对象发送消息(调用方法).  也就是说,所有的包含关系都应当是使用关系. 如果不是这样,那么包含的类有什么用处呢?当然,面向过程的开发人员会想 ...

  9. Entity Framework 异常档案

    1.异常 The model backing the 'DBContext' context has changed since the database was created.Consider u ...

  10. [转+原]chrony

    greenplum,openstack等云计算项目需要集群服务器部署,服务器之间的时间需要同步,但并不是所有机器可以 直接连外网,这时可以用Chrony工具解决. 解决方法是将其中一台设为时间服务器, ...