Cloneable是標記型的介面(空介面),它們內部都沒有方法與屬性,實作Cloneable來表示該物件能被複製,能使用Object.clone()方法。如果沒有實作 Cloneable的類別物件呼叫clone()就會拋出CloneNotSupportedException異常。
可以理解為Cloneable介面發揮的是標記功能,自訂型別需要使用者自己標記出哪些類別是可以clone的,這個標記就是去實作Cloneable接口,實現了Cloneable介面後就表示該類別所建立的物件可以被克隆。
而要想使一個類別具備拷貝實例的功能,除了要實作Cloneable接口,還必須重寫Object類別的clone()方法。
可以看到Object類別的clone()方法是被protected修飾的,所以需要在重寫的clone()方法中透過super關鍵字去呼叫Object類中的clone()方法
在拷貝一個物件時,對物件的基本資料類型的成員變量進行拷貝,但對引用類型的成員變數只進行引用的傳遞,並沒有創建一個新的對象,當對引用類型的內容修改會影響被拷貝的對象。簡而言之:淺拷貝僅僅複製所拷貝的對象,而不複製它所引用的對象。
觀察下面的程式碼,將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); } }
執行結果:
淺拷貝圖解:
在拷貝一個物件時,除了對基本資料類型的成員變數進行拷貝,對引用類型的成員變數進行拷貝時,建立一個新的物件來保存引用類型的成員變數。簡而言之:深拷貝把要複製的物件所引用的物件都複製了一遍。
下面的程式碼實現了深拷貝;實現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); } }
執行結果:
深度拷貝圖解:
java中clone方法是一個淺拷貝,引用類型依然在傳遞引用。我們可以透過繼續呼叫clone()方法,對 該物件的參考類型變數再實作一次clone()的方法來實現深拷貝。
以上是Java深拷貝,淺拷貝和Cloneable介面怎麼用的詳細內容。更多資訊請關注PHP中文網其他相關文章!