天天看點

使用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.

// clone() is now overridden and is public.

public Object clone() {

return super.clone();

class CloneDemo2 {

// here, clone() is called directly.

x2 = (TestClone) x1.clone();

由複制帶來的副作用最初一般是比較難發現的。通常很容易想到的是類在複制時是很安全的,而實際卻不是這樣。一般在沒有一個必須的原因的情況下,對任何類都不應該執行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 {  

要實作深複制,需要采用流的形式讀入目前對象的二進制輸入,再寫出二進制資料對應的對象。

    本文轉自 一點點征服   部落格園部落格,原文連結:http://www.cnblogs.com/ldq2016/p/5231832.html,如需轉載請自行聯系原作者