Java中的clone()方法有什麼作用
阿新 • • 發佈:2018-11-11
Java在處理基本資料型別(例如int、char、double等)時,都是採用值傳遞(傳遞的是輸入引數的副本)的方式執行,除此之外的其它型別(物件啊,String型別等)都是按引用傳遞(傳遞的是物件的一個引用)的方式執行。物件除了在函式呼叫時是引用傳遞,在使用“=”也是採用引用傳遞
class Obj { private int i = 0; public int getI() { return i; } public void setI(int i) { this.i = i; } public void changeI() { this.i = 1; } } public class LianXi { public static void main(String[] args) { Obj a = new Obj(); Obj b = a; b.changeI(); System.out.println("a:"+a.getI()); System.out.println("b:"+b.getI()); } }
執行結果:
a:1
b:1
在實際程式設計中,經常需要從某個已知物件A創建出另一個與A具有相同狀態的物件B,並且對B的修改不會影響到A的狀態,但從上面的例項中,我們會發現僅僅通過簡單的賦值操作顯然是無法達到這個目的的(b物件對i的修改影響到了a物件中的i),所以Java提供了一個簡單有效的clone()方法來滿足這個需求。
Java中所有的類都預設繼承自Object類,而Object類中提供了一個clone()方法,這個方法的作用是返回一個Object物件的複製,這個複製方法返回的是一個新的物件而不是一個引用。以下是使用clone()方法的步驟:
- 實現clone的類首先需要繼承Cloneable介面(Cloneable介面實質是一個標識介面,沒有任何的介面方法)
- 在類中重寫Object類中的clone()方法
- 在clone()方法中呼叫super.clone()。無論clone類繼承結構是什麼,super.clone()會直接或間接java.lang.Object類中的clone()方法。
- 把淺複製的引用指向原型物件新的克隆體。
上面的例子引入clone()方法後代碼:
class Obj implements Cloneable { private int i = 0; public int getI() { return i; } public void setI(int i) { this.i = i; } public void changeI() { this.i = 1; } public Object clone() { //重寫clone()方法 Object o = null; try { o = (Obj)super.clone(); }catch(CloneNotSupportedException e) { e.printStackTrace(); } return o; } } public class LianXi { public static void main(String[] args) { Obj a = new Obj(); Obj b = (Obj)a.clone(); b.changeI(); System.out.println("a:"+a.getI()); System.out.println("b:"+b.getI()); } }
在開發人員自定義複製建構函式時,會存在淺複製和深複製之分,Java在過載clone()方法時也存在同樣的問題,當類中只有一些基本資料型別時,採用上述的方法就可以了,但是當類中包含了一些物件時,就需要用到深複製了(沒錯,上面那個就是淺複製),實現方法是在對物件呼叫clone()方法完成複製後,接著對物件中的非基本資料型別的屬性也呼叫clone()方法完成深複製,例項如下:
class Obj implements Cloneable {
private Date birth = new Date(); //物件
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public void changeDate() {
this.birth.setMonth(4);
}
public Object clone() {
Obj o = null;
try {
o = (Obj)super.clone(); //先執行淺複製
}catch(CloneNotSupportedException e) {
e.printStackTrace();
}
o.birth = (Date)this.getBirth().clone(); //深複製,沒有這一步的話,兩個對
//象的執行結果都是4月,原因是後面的深複製和淺複製的區別
return o;
}
}
public class LianXi {
public static void main(String[] args) {
Obj a = new Obj();
Obj b = (Obj)a.clone();
b.changeDate();
System.out.println("a:"+a.getBirth());
System.out.println("b:"+b.getBirth());
}
}
執行結果:
a:Tue Sep 25 13:14:44 CST 2018
b:Fri May 25 13:14:44 CST 2018
深複製和淺複製的區別:
- 淺複製:被複制物件的所有變數都含有與原來物件相同的值,而所有對其他物件的引用任然指向原來的物件,換言之,淺複製僅僅複製所考慮的物件,而不復制它所引用的物件
- 深複製:被複制物件的所有變數都含有與原來物件相同的值,除去那些引用其他物件的變數,那些引用其他物件的變數將指向被複制的新物件,而不知原來那些被引用的物件,換言之,深複製把淺複製的物件所引用的物件都複製了一遍。