使用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 plain copy

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

 

 
要實現深復制,需要采用流的形式讀入當前對象的二進制輸入,再寫出二進制數據對應的對象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM