天天看點

java對象 深度克隆(不實作Cloneable接口)和淺度克隆

為什麼需要克隆:

在實際程式設計過程中,我們常常要遇到這種情況:有一個對象a,在某一時刻a中已經包含了一些有效值,此時可能會需要一個和a完全相同新對象b,并且此後對b任何改動都不會影響到a中的值,也就是說,a與b是兩個獨立的對象,但b的初始值是由a對象确定的。在java語言中,用簡單的指派語句是不能滿足這種需求的,要滿足這種需求有很多途徑。

克隆的實作方式

一、淺度克隆

對于要克隆的對象,對于其基本資料類型的屬性,複制一份給新産生的對象,對于非基本資料類型的屬性,僅僅複制一份引用給新産生的對象,即新産生的對象和原始對象中的非基本資料類型的屬性都指向的是同一個對象

1、實作java.lang.cloneable接口

要clone的類為什麼還要實作cloneable接口呢?cloneable接口是一個辨別接口,不包含任何方法的!這個辨別僅僅是針對object類中clone()方法的,如果clone類沒有實作cloneable接口,并調用了object的 clone()方法(也就是調用了super.clone()方法),那麼object的clone()方法就會抛出 clonenotsupportedexception異常。

2、重寫java.lang.object.clone()方法

jdk api的說明文檔解釋這個方法将傳回object對象的一個拷貝。要說明的有兩點:一是拷貝對象傳回的是一個新對象,而不是一個引用。二是拷貝對象與用new操作符傳回的新對象的差別就是這個拷貝已經包含了一些原來對象的資訊,而不是對象的初始資訊。

觀察一下object類的clone()方法是一個native方法,native方法的效率一般來說都是遠高于java中的非native方法。這也解釋了為什麼要用object中clone()方法而不是先new一個類,然後把原始對象中的資訊賦到新對象中,雖然這也實作了clone功能。object類中的clone()還是一個protected屬性的方法,重寫之後要把clone()方法的屬性設定為public。

object類中clone()方法産生的效果是:先在記憶體中開辟一塊和原始對象一樣的空間,然後原樣拷貝原始對象中的内容。對基本資料類型,這樣的操作是沒有問題的,但對非基本類型變量,我們知道它們儲存的僅僅是對象的引用,這也導緻clone後的非基本類型變量和原始對象中相應的變量指向的是同一個對象。

java代碼

public class product implements cloneable {   

    private string name;   

    public object clone() {   

        try {   

            return super.clone();   

        } catch (clonenotsupportedexception e) {   

            return null;   

        }   

    }   

}  

二、深度克隆

在淺度克隆的基礎上,對于要克隆的對象中的非基本資料類型的屬性對應的類,也實作克隆,這樣對于非基本資料類型的屬性,複制的不是一份引用,即新産生的對象和原始對象中的非基本資料類型的屬性指向的不是同一個對象

要克隆的類和類中所有非基本資料類型的屬性對應的類

1、都實作java.lang.cloneable接口

2、都重寫java.lang.object.clone()方法

public class attribute implements cloneable {   

    private string no;   

}   

    private attribute attribute;   

三、使用對象序列化和反序列化實作深度克隆

所謂對象序列化就是将對象的狀态轉換成位元組流,以後可以通過這些值再生成相同狀态的對象。

對象的序列化還有另一個容易被大家忽略的功能就是對象複制(clone),java中通過clone機制可以複制大部分的對象,但是衆所周知,clone有深度clone和淺度clone,如果你的對象非常非常複雜,并且想實作深層 clone,如果使用序列化,不會超過10行代碼就可以解決。

雖然java的序列化非常簡單、強大,但是要用好,還有很多地方需要注意。比如曾經序列化了一個對象,可由于某種原因,該類做了一點點改動,然後重新被編譯,那麼這時反序列化剛才的對象,将會出現異常。 你可以通過添加serialversionuid屬性來解決這個問題。如果你的類是個單例(singleton)類,是否允許使用者通過序列化機制複制該類,如果不允許你需要謹慎對待該類的實作。

public class attribute {   

public class product {   

    public product clone() {   

        bytearrayoutputstream byteout = null;   

        objectoutputstream objout = null;   

        bytearrayinputstream bytein = null;   

        objectinputstream objin = null;   

            byteout = new bytearrayoutputstream();    

            objout = new objectoutputstream(byteout);    

            objout.writeobject(prototype);   

            bytein = new bytearrayinputstream(byteout.tobytearray());   

            objin = new objectinputstream(bytein);   

            return (contreteprototype) objin.readobject();   

        } catch (ioexception e) {   

            throw new runtimeexception("clone object failed in io.",e);      

        } catch (classnotfoundexception e) {   

            throw new runtimeexception("class not found.",e);      

        } finally{   

            try{   

                bytein = null;   

                byteout = null;   

                if(objout != null) objout.close();      

                if(objin != null) objin.close();      

            }catch(ioexception e){      

            }      

特别說明:尊重作者的勞動成果,轉載請注明出處哦~~~