天天看點

java深克隆 淺克隆_通過Java中深克隆與淺克隆來了解克隆

面試時的尴尬瞬間

聊到克隆,不禁想起了自己懵懂無知時的一個面試。

面試官:Java中建立對象的方式有哪些?

我:有構造方法、反射,其他的應該沒了吧。

然後面試官笑笑沒說話,面試差不多結束時。

我:Java中建立對象的方式還有哪些?

面試官:還有序列化和克隆。

我:...

面試官:...

......

回到家後就檢視了相關的部落格資料,先對克隆做進一步的了解。看過之後還是一知半解的狀态,就在最近學習的一個視訊中,老師對這部分進行講解後,我才有了一種豁然開朗感覺,希望在這裡分享給大家。

下面我就照着自己的了解,通過講述克隆中的深克隆與淺克隆,來讓大家能夠了解克隆這樣一個概念,希望大家以後在面試或工作中都能夠用到。

廢話不多說,由淺入深,直接來Coding、Debug

淺克隆

一、建立一個基礎類Person,擁有屬性name(基礎資料類型)和birthday(引用資料類型),并讓其通過實作Cloneable接口并重寫clone方法來實作克隆。

(杠精注意:這裡必須要實作Cloneable接口和重寫clone方法才能實作克隆,當然你說我通過繼承父類的,那我隻能說你能實作就好。)

public class Person implements Cloneable {

private String name;

private Date birthday;

public Person() {}

public Person(String name, Date birthday) {

this.name = name;

this.birthday = birthday;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Date getBirthday() {

return birthday;

}

public void setBirthday(Date birthday) {

this.birthday = birthday;

}

@Override

protected Object clone() throws CloneNotSupportedException {

return super.clone();

}

}

二、建立一個測試類進行測試,經過克隆後的對象還是不是同一個對象?

@Test

public void test1() throws CloneNotSupportedException {

Person person1 = new Person("lihui", new Date(0L));

Person person2 = (Person) person1.clone();

System.out.println(person1);

System.out.println(person2);

System.out.println(person1 == person2);

}

結果分析:

1、列印結果(1、2行)列印的(類名 + @ + hashcode轉16進制)是不同的。這個你想讓它看起來相同也很簡單,你就重寫hashCode方法就行了。(因為我在使用lombok的Data注解時,就因為它會自動重寫hashCode方法,我當時看到的他們就是相同的);

2、列印結果(3行)列印的兩者比較的值是不同的,說明已經克隆出了一個新對象。

三、Debug進一步檢視對象的實際記憶體配置設定,跑起來...

java深克隆 淺克隆_通過Java中深克隆與淺克隆來了解克隆

淺克隆記憶體分析圖

結果分析:

1、這裡假設數字就是記憶體位址:person1的記憶體位址是861,person2的記憶體位址是882,他們的記憶體位址是不同的,是以上述中的比較結果自然是:false;

2、仔細看圖你會發現person1和person2的引用類型屬性birthday的記憶體位址是相同的,奧,,,原來它僅僅克隆了這個對象最表層的東西,内部的引用類型屬性都沒改變,是以預設重寫的clone方法是一種淺克隆。

(有多淺,就像你去遊泳,遊泳池的水才到你的腳面。)

注意:在這種預設重寫的clone方法下,一個對象A被建立了,然後對象B是通過對象A克隆得到的,那麼僅僅是對象A的記憶體位址與對象B的記憶體位址不同,它們内部的引用類型屬性還都是相同的。

顯然:這種淺克隆的方式克隆出來的對象,不一定是我們想要的那種對象,是以有興趣的同學接着學習下面的深克隆。

深克隆

一、在淺克隆的基礎上,再次重寫clone方法,目的是不僅要克隆這個對象本身,我還要克隆這個對象中的引用類型屬性。

(你這時要跟從業人員說一下,我是來遊泳的,不是來洗腳的,你再給我加點水。)

@Override

protected Object clone() throws CloneNotSupportedException {

Person person = (Person) super.clone();

// 這裡對對象内的引用類型屬性進行克隆,使克隆更深入

person.birthday = (Date) person.birthday.clone();

return person;

}

二、直接Debug檢視再次重寫後的clone方法克隆的結果:

java深克隆 淺克隆_通過Java中深克隆與淺克隆來了解克隆

深克隆記憶體分析圖

結果分析:

1、person1與person2的記憶體位址跟淺克隆情況下的分析結果相同,也是不一樣的;

2、仔細看圖你會發現person1和person2的引用類型屬性birthday他們的記憶體位址值也不一樣啦,是以經過再次重寫後的clone方法我們稱之為深克隆。

(這下水就到腰了,可以愉快地遊泳啦。)

顯然:經過深克隆的方式克隆出來的對象,可能是我們想要的對象。

當然這隻是一個簡單的例子,讀者也可以找一些複雜的引用類型屬性(如:對象、集合等)來編寫測試案例玩一玩。

如果想深入學習,可以檢視一些實作了Cloneable接口的源碼的clone方法來進行學習,我相信你肯定不會去看,是以就當我沒說好啦。

很高興完成了這個部落格,有什麼寫不對的地方請您在下方留言指出。

如果您對深克隆和淺克隆的概念還是不大懂,那請您在下方留下您的支*寶賬号,将會有一筆巨額資金打入您的賬戶,讓我們一起學習慕*網的Java設計模式精講。

成長的路上,希望有你有我。