Java的clone機制及其重要的可變類與不可變類要義

 

當方法中傳遞的參數是基本數據類型時,採用的是值傳遞;當輸入參數是對象時,採用的是引用傳遞。這是“影子克隆(shallow clone)”。如果想要按值傳遞參數,該類就要實現cloneable接口,並實現clone方法,將“對象名.clone()”做參數傳遞(deep clone)

     Object 類有 clone() 方法: protected native Object clone() throws CloneNotSupportedException;

     該方法是 protected 的,顯然是留待被子類 override 的。該方法又是 native 的,必然做了與具體平臺相關的底層工作。

     事實上,類 Object clone() 方法首先會檢查 this.getClass() 是否實現了 Cloneable 接口。 Cloneable 只是一個標誌接口而已,用來標誌該類是否有克隆功能。

public interface Cloneable {

}

     如果 this.getClass() 沒有實現 Cloneable 接口, clone() 就會拋 CloneNotSupportedException 返回。否則就會創建一個類型爲 this.getClass() 的對象 other ,並將   this field 的值賦值給 other 的對應 field 若是基本數據類型及非可變類類型的field則是按值,若可變類類型則按引用賦值然後返回 other

 

所謂不可變類,是指當創建了這個類的實例後,就不允許修改它的屬性值。 它包括:

primitive變量: boolean,byte, char, double ,float, integer, long, short

jdk的不可變類:jdkjava.lang包中 Boolean, Byte, Character, Double, Float, Integer, Long, Short, String

可變類,是當你獲得這個類的一個實例引用時,你可以改變這個實例的內容。 可變類對象間用“=”賦值,則會是使兩個對象實際上會引用同一個實例。所以,只有實現深度clone才能使可變類對象的修改不影響原始對象的值。然而,對於不可變類,可變類的特性也是很有意義的,有的時候我們不希望重複創建相同的內容的實例。因此,我們也可以利用不可變類獲得實例緩存。如:

 

Integer a=Integer.valueOf(10);

Integer b= Integer.valueOf(10);

則只會在第一次創建取值爲10Integer對象。也就是說ab指向同一處內存上的內容。

 

那應該如何創建一個自己的不可變類:

·所有成員都是private

·不提供對成員的改變方法,例如:setXXXX

·確保所有的方法不會被重載。手段有兩種:使用final Class(強不可變類),或者將所有類方法加上final(弱不可變類)

·如果某一個類成員不是原始變量(primitive)或者不可變類,必須通過在成員初始化(in)或者get方法(out)時通過深度clone方法,來確保類的不可變。

反言之,任何提供了外部可修改途徑的自定義類都是可變類。因而,只有實現深度clone才能使可變類對象按值賦給另一個對象,而不是按引用。例如,在自定義的類 A 中,假設用戶聲明一個不可變類 B field,並提供了可修改 B 值的途徑。顯然,A便因此成爲一個可變類,儘管它包括有不可變類的字段,或者根本沒有可變類的字段。

 

 

參考:

孫衛琴,《JAVA面向對象編程》,2006年版

Roger Tu,Java Clone機制》,20073月,http://www.blogjava.net/RogerTwain

冠林,《可變類和不可變類(Mutable and Immutable Objects)》,20079http://hi.baidu.com/%D5%C5%B9%DA%C1%D6/blog/item/f0aaa8af98eaafcf7cd92ab3.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章