詳解Java深拷貝,淺拷貝和Cloneable接口
1. Cloneable接口的介紹
Cloneable是標記型的接口(空接口),它們內部都沒有方法和屬性,實現 Cloneable來表示該對象能被克隆,能使用Object.clone()方法。如果沒有實現 Cloneable的類對象調用clone()就會拋出CloneNotSupportedException異常。
可以理解為Cloneable接口發揮的是標記功能,自定義類型需要用戶自己標記出哪些類是可以clone的,這個標記就是去實現Cloneable接口,實現瞭Cloneable接口後就表明該類創建的對象可以被克隆。
而要想使一個類具備拷貝實例的功能,除瞭要實現Cloneable接口,還必須重寫Object類的clone()方法。
可以看到Object類的clone()方法是被protected修飾的,所以需要在重寫的clone()方法中通過super關鍵字去調用Object類中的clone()方法
2. 淺拷貝的介紹和實例
在拷貝一個對象時,對 對象的基本數據類型的成員變量進行拷貝,但對引用類型的成員變量隻進行引用的傳遞,並沒有創建一個新的對象,當對引用類型的內容修改會影響被拷貝的對象。簡而言之:淺拷貝僅僅復制所拷貝的對象,而不復制它所引用的對象。
觀察下面的代碼,將Money類的實例作為瞭Person類的字段,new一個Person類的對象person1,將這個person1對象拷貝到person2中,這裡的拷貝就是淺拷貝瞭,隻是將person1對象的money引用拷貝到瞭person2,person1和person2中的momey指向的是同一個對象。
class Money { public double m = 666; } class Person implements Cloneable{ int id; public Money money = new Money(); public Person(int id) { this.id = id; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Person{" + "id=" + id + ", money=" + money.m + '}'; } } public class TestDemo3 { public static void main(String[] args) throws CloneNotSupportedException { Person person1 = new Person(1); Person person2 = (Person) person1.clone(); System.out.println("通過person2修改前的結果"); System.out.println(person1); System.out.println(person2); person2.money.m = 888; person2.id = 2; System.out.println("通過person2修改後的結果"); System.out.println(person1); System.out.println(person2); } }
執行結果:
淺拷貝圖解:
3. 深拷貝的介紹和實例
在拷貝一個對象時,除瞭對基本數據類型的成員變量進行拷貝,對引用類型的成員變量進行拷貝時,創建一個新的對象來保存引用類型的成員變量。簡而言之:深拷貝把要復制的對象所引用的對象都復制瞭一遍。
下面的代碼實現瞭深拷貝;實現person1對象的深拷貝,先用Person tmp引用來保存淺拷貝的結果,通過tmp引用找到money對象,再將money對象拷貝一份,然後賦值給tmp中的money,最後返回tmp即可。這樣就將money引用的對象也拷貝瞭一份,實現瞭深拷貝,此時person1和person2中的momey指向的是兩個不同的對象。
class Money implements Cloneable{ public double m = 666; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable{ public int id; public Money money = new Money(); public Person(int id) { this.id = id; } @Override protected Object clone() throws CloneNotSupportedException { //return super.clone(); Person tmp = (Person) super.clone(); tmp.money = (Money) this.money.clone(); return tmp; } @Override public String toString() { return "Person{" + "id=" + id + ", money=" + money.m + '}'; } } public class Test2 { public static void main(String[] args) throws CloneNotSupportedException{ Person person1 = new Person(1); Person person2 = (Person) person1.clone(); System.out.println("通過person2修改前的結果"); System.out.println(person1); System.out.println(person2); person2.money.m = 888; person2.id = 2; System.out.println("通過person2修改後的結果"); System.out.println(person1); System.out.println(person2); } }
執行結果:
深拷貝圖解:
4. clone方法總結
java中clone方法是一個淺拷貝,引用類型依然在傳遞引用。我們可以通過繼續調用clone()方法,對 該對象的引用類型變量再實現一次clone()的方法來實現深拷貝。
到此這篇關於詳解Java深拷貝,淺拷貝和Cloneable接口的文章就介紹到這瞭,更多相關Java Cloneable接口內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!