當方法中傳遞的參數是基本數據類型時,採用的是值傳遞;當輸入參數是對象時,採用的是引用傳遞。這是“影子克隆(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的不可變類:jdk的java.lang包中 Boolean, Byte, Character, Double, Float, Integer, Long, Short, String
可變類,是當你獲得這個類的一個實例引用時,你可以改變這個實例的內容。 可變類對象間用“=”賦值,則會是使兩個對象實際上會引用同一個實例。所以,只有實現深度clone才能使可變類對象的修改不影響原始對象的值。然而,對於不可變類,可變類的特性也是很有意義的,有的時候我們不希望重複創建相同的內容的實例。因此,我們也可以利用不可變類獲得實例緩存。如:
Integer a=Integer.valueOf(10);
Integer b= Integer.valueOf(10);
則只會在第一次創建取值爲10的Integer對象。也就是說a和b指向同一處內存上的內容。
那應該如何創建一個自己的不可變類:
·所有成員都是private
·不提供對成員的改變方法,例如:setXXXX
·確保所有的方法不會被重載。手段有兩種:使用final Class(強不可變類),或者將所有類方法加上final(弱不可變類)。
·如果某一個類成員不是原始變量(primitive)或者不可變類,必須通過在成員初始化(in)或者get方法(out)時通過深度clone方法,來確保類的不可變。
反言之,任何提供了外部可修改途徑的自定義類都是可變類。因而,只有實現深度clone才能使可變類對象按值賦給另一個對象,而不是按引用。例如,在自定義的類 A 中,假設用戶聲明一個不可變類 B 的field,並提供了可修改 B 值的途徑。顯然,A便因此成爲一個可變類,儘管它包括有不可變類的字段,或者根本沒有可變類的字段。
參考:
孫衛琴,《JAVA面向對象編程》,2006年版
Roger Tu,《Java Clone機制》,2007年3月,http://www.blogjava.net/RogerTwain
冠林,《可變類和不可變類(Mutable and Immutable Objects)》,2007年9月http://hi.baidu.com/%D5%C5%B9%DA%C1%D6/blog/item/f0aaa8af98eaafcf7cd92ab3.html