什么是別名? 用個(gè)簡單的例子說明 public class Aliases{ int i; public Aliases() { i=1; } public Aliases(int i) { this.i=i; } public static void main(String args[]) { Aliases A=new Aliases(); Aliases B=A; //A和B指向了同一個(gè)對象,A和B互為別名 System.out.println("A.i and B.i:"+A.i+" "+B.i); System.out.println("增加B:"); B.i++; System.out.println(("A.i and B.i:"+A.i+" "+B.i); } } 輸出:A.i and B.i:1 1 增加B: A.i and B.i:2 2 很明顯,A和B指向了同一個(gè)對象,B=A這個(gè)操作只是把A的引用復(fù)制給了B,而對象并未拷貝。java是通過Rerference來操作對象的,上面是一個(gè)顯式別名的例子,當(dāng)你往函數(shù)內(nèi)傳遞對象時(shí)也會(huì)發(fā)生別名,如下: public class Aliases{ int i; public Aliases() { i=1; } public Aliases(int i) { this.i=i; } public Increment(Aliases AS) { AS.i++; } public static void main(String args[]) { Aliases A=new Aliases(); System.out.println("A.i before Increment:"+A.i); Increment(A); System.out.println("A.i after Increment:"+A.i); } } 你可以看到A在經(jīng)過函數(shù)Increment()的調(diào)用后i的值發(fā)生了變化。在某種情況下,你可能不希望傳入的對象發(fā)生變化,希望函數(shù)內(nèi)的對象只是傳入對象 的副本,對這個(gè)副本的改變不至于影響原來的對象,那該如何處理?我們知道C++是通過把參數(shù)聲明了const,就意味著此參數(shù)不可改變,但是別忘了,C+ +有所謂的拷貝構(gòu)造函數(shù),所以在函數(shù)中的對象確實(shí)是拷貝,而java并未支持拷貝構(gòu)造函數(shù),原因很明顯,java傳遞對象的引用,你就算拷貝也只是引用的 拷貝而已(所以有人說java本質(zhì)上只有傳值)。那么就沒辦法了嗎?有的,那就是“克隆機(jī)制”,在根類Object已經(jīng)定義了clone()方法,你所要 做的只是實(shí)現(xiàn)cloneable接口,并覆寫clone()方法,典型的應(yīng)用如下 class CloneClass implements Cloneable{ public int aInt; public Object clone(){ CloneClass o = null; try{ o = (CloneClass)super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return o; } } 調(diào) 用super.clone()方法,它會(huì)為你自動(dòng)處理存儲分配和復(fù)制操作,從而實(shí)現(xiàn)了對象的深層拷貝。我們又知道,同過serilization也可以實(shí) 現(xiàn)對象的深層拷貝啊,為什么不用這個(gè)?根本原因在于效率上的巨大差異,clone()雖然一開始好象很復(fù)雜,但畢竟沒有對象的讀寫那么耗費(fèi)資源。有了 clone機(jī)制,你就可以在方法調(diào)用內(nèi)部制造一個(gè)對象的副本了,它是局域性,對它的任何操作都不至于影響原對象的狀態(tài)了。我個(gè)人認(rèn)為,這點(diǎn)對于編寫一個(gè)安 全的大型程序是非常重要的。 |
|