使用clone( )和Cloneable接口

由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。

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

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

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

[java] view plaincopy

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;
  • }

要实现深复制,需要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。

时间: 2024-08-01 10:33:14

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

Cloneable接口和Object的clone()方法

http://www.cnblogs.com/xrq730/p/4858937.html 为什么要克隆 为什么要使用克隆,这其实反映的是一个很现实的问题,假如我们有一个对象: public class SimpleObject implements Cloneable { private String str; public SimpleObject() { System.out.println("Enter SimpleObject.constructor()"); } public

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

Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么要对对象进行克隆.Java中所有的对象都是保存在堆中,而堆是供全局共享的.也就是说,如果同一个Java程序的不同方法,只要能拿到某个对象的引用,引用者就可以随意的修改对象的内部数据(前提是这个对象的内部数据通过get/set方法曝露出来).有的时候,我们编写的代码想让调用者只获得该对象的一个拷贝(也

关于Cloneable接口和clone方法

1.使用 创建对象有两种方式: new 和 clone 当一个对象创建过程复杂,我们是否可以根据已有的对象直接来克隆一份,而不必关系创建的细节呢(原型模式). 1.1 Java Object根类默认提供了clone方法: protected native Object clone() throws CloneNotSupportedException; 一个本地方法,protected权限: 这样做是为避免我们创建每一个类都默认具有克隆能力 1.2 实现Cloneable接口 我们要使用一个对象

Cloneable接口和循环冗余校验算法

1 Cloneable 接口 实现该接口的类可以调用clone()方法合法地对该类实例进行按字段复制.按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的) 2 循环冗余校验算法 循环冗余校验(英语:Cyclic redundancy check,通称“CRC”)是一种根据网络数据数据包或计算机文件等数据产生简短固定位数校验码的一种散列函數,主要用来检测或校验数据传输或者保存后可能出现的错误.生成的数字在传输或者存储之前计算出来并且附加到数据后面,然后接收方进行检

Java中的深克隆和浅克隆——Cloneable接口

一.没有使用克隆带来的问题 public class CloneTest { static Student s = new Student("aaa", 20); // 直接赋值带来的问题 public static void noclone() { // 传的是引用的副本,改变了noCloneStudent也改变了s Student noCloneStudent = new Student(); noCloneStudent = s; noCloneStudent.setName(&

Cloneable接口的作用

Cloneable接口是一个[标记接口],就是没有任何内容 implements Cloneable表示该对象能被克隆,能使用Object.clone()方法.如果没有implements Cloneable的类调用Object.clone()方法就会抛出CloneNotSupportedException. 原文地址:https://www.cnblogs.com/yourGod/p/Cloneable.html

创建对象的第二种方式:克隆clone,要实现Cloneable接口

1 ackage com.wisezone.clone; 2 3 /** 4 * 空接口: 5 * 标识,告诉JVM,通行 6 * 1.克隆 7 * 2.序列化 8 * 9 * 创建对象的第二种方式:克隆clone,要实现Cloneable 10 * @author 王东海 11 * @2017年4月15日 12 */ 13 public class TestClone implements Cloneable 14 { 15 public String name; 16 17 public s

Cloneable接口的使用

1.implements Cloneable 2. 1 public PortfolioInstrumentMetric clone() { 2 PortfolioInstrumentMetric o = null; 3 try { 4 o = (PortfolioInstrumentMetric) super.clone(); 5 } catch (CloneNotSupportedException e) { 6 e.printStackTrace(); 7 } 8 return o; 9

Cloneable 接口是不是一个鸡肋?

Josh Bloch:如果你在我的书中读到关于克隆的文章,特别是当你在字里行间读到的时候,你就会知道我认为克隆已经被深深地破坏了.有一些设计缺陷,其中最大的一个是可克隆的接口没有克隆方法.这就意味着它根本就不起作用:制造一些可克隆的东西并不能说明你能用它做什么.相反,它说明了它在内部可以做些什么.它说,如果通过调用super.重复克隆结束调用对象的克隆方法,该方法将返回原始的字段副本.但它并没有说明你能用一个实现可克隆界面的对象做什么,这意味着你不能做多态克隆操作.如果我有一个Cloneable