博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用clone( )和Cloneable接口
阅读量:4577 次
发布时间:2019-06-08

本文共 3643 字,大约阅读时间需要 12 分钟。

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

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

 

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

转载于:https://www.cnblogs.com/ldq2016/p/5231832.html

你可能感兴趣的文章
C++ Primer
查看>>
[转]Android OpenGL ES 开发教程 从入门到精通
查看>>
算法入门笔记------------Day4
查看>>
.net学习笔记之访问数据库
查看>>
JavaScript数组常用的方法
查看>>
洛谷 P1402 酒店之王
查看>>
linux日常管理-系统服务
查看>>
Enter Query Mode Search Tricks Using Enter_Query Built-in in Oracle Forms
查看>>
Form属性、内置子程序、触发器、系统变量
查看>>
广州夜景一
查看>>
linux编译安装python3和安装django
查看>>
PHP数组对象互转
查看>>
JVM(2)--一文读懂垃圾回收
查看>>
NyistOJ 55 懒省事的小明(c++)(优先队列)(贪心)
查看>>
iOS ERROR: unable to get the receiver data from the DB 解决方式
查看>>
游戏开发——战斗系统设计技巧
查看>>
Android ROM 制作教程
查看>>
Android模拟器使用SD卡
查看>>
新手Oracle安装及使用入门
查看>>
4/25
查看>>