關(guān)于Java的淺拷貝和深拷貝

淺拷貝和深拷貝是什么稚虎?

淺拷貝和深拷貝都是針對已經(jīng)存在了的對象的操作砂代,在java中,基本數(shù)據(jù)類型有八種,和引用數(shù)據(jù)類型桩撮。在程序中,一般用 = 來做賦值的操作崔兴,對于基本數(shù)據(jù)類型印机,實際上是拷貝它的值,而對于引用數(shù)據(jù)類型鞭衩,則是拷貝的它的引用地址学搜,舉例如下:

@Test
public void m2() {
    int i = 1;
    int j = i;
    System.out.println(j);

    Student stu1 = new Student("zhangsan", 12);
    System.out.println(stu1);
    Student stu2 = stu1;
    stu2.setAge(20);
    System.out.println(stu1);
    System.out.println(stu2);
}

運(yùn)行結(jié)果:

1
Student{name='zhangsan', age=12, active=null}
Student{name='zhangsan', age=20, active=null}
Student{name='zhangsan', age=20, active=null}

從運(yùn)行的結(jié)果,發(fā)現(xiàn)一個問題论衍,int類型的值不用多說瑞佩,而在引用類型中,明明修改的是stu2的age坯台,為什么stu1的age也發(fā)生了變化炬丸,這里就涉及到了值傳遞和引用傳遞的問題了,ok蜒蕾,后面介紹稠炬。

Java中的clone()方法

說到拷貝操作,那java必定提供了API來供我們使用滥搭,那就是Object類中的clone()方法了(它是一個native方法)酸纲,既然是超類中的protected方法,那么子類中就有必要重寫一下瑟匆,所有使用調(diào)用clone()來拷貝的時候闽坡,其對象必須要實現(xiàn)標(biāo)識接口Cloneable,否則就會拋出CloneNotSupportedException這個異常愁溜。

淺拷貝

首先創(chuàng)建一個Studen類疾嗅,并實現(xiàn)Cloneable接口,重寫clone方法冕象。

public class Student implements Cloneable {

    private String name;

    private int age;

    private Active active;

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    // 省略get代承、set方法

}

Active類的實現(xiàn):

public class Active implements Cloneable {

    private String name;

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Active(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

測試用例:用clone方法,復(fù)制新new出來的student1渐扮,得到student2,再做各種比較论悴。

@Test
public void m1() throws Exception {
    Student student1 = new Student();
    student1.setAge(10);
    student1.setName("zhangsan");
    student1.setActive(new Active("pingpang"));
    // 原始對象的hashcode
    System.out.println(student1.hashCode());
    // 克隆出來的對象
    Student student2 = (Student) student1.clone();
    // 克隆出來的對象的hashcode
    System.out.println(student2.hashCode());
    // 兩個對象是否一樣
    System.out.println(student1 == student2);
    // 兩個對象比較
    System.out.println(student1);
    System.out.println(student2);
    // 兩個對象各自的引用比較
    System.out.println(student1.getActive());
    System.out.println(student2.getActive());
}

運(yùn)行結(jié)果:

697960108
943010986
false
Student@299a06ac
Student@383534aa
Active@6bc168e5
Active@6bc168e5

可以得出關(guān)于淺拷貝的幾點結(jié)論:

  • clone()方法掖棉,會創(chuàng)建一個新的對象。
  • 淺拷貝基本數(shù)據(jù)類型是拷貝值膀估。
  • 拷貝引用數(shù)據(jù)類型如:Active 幔亥,則拷貝的是它的引用地址。

深拷貝

Student類察纯,在克隆此類對象的時候帕棉,將此對象中的引用屬性也克隆一份,只有clone方法不同:

public class Student implements Cloneable {

    private String name;

    private int age;

    private Active active;

    public Object clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        student.active = (Active) this.active.clone();
        return student;
    }

    // get饼记、set方法省略

}

Active類香伴,實現(xiàn)Cloneable接口,并重寫了clone方法:

public class Active implements Cloneable {

    private String name;

    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Active(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

測試用例:

@Test
public void m1() throws Exception {
    Student student1 = new Student();
    student1.setAge(10);
    student1.setName("zhangsan");
    student1.setActive(new Active("pingpang"));
    // 原始對象的hashcode
    System.out.println(student1.hashCode());
    // 克隆出來的對象
    Student student2 = (Student) student1.clone();
    // 克隆出來的對象的hashcode
    System.out.println(student2.hashCode());
    // 兩個對象是否一樣
    System.out.println(student1 == student2);
    // 兩個對象比較
    System.out.println(student1);
    System.out.println(student2);
    // 兩個對象各自的引用比較
    System.out.println(student1.getActive());
    System.out.println(student2.getActive());
}

測試結(jié)果中顯示不同student對象中的active對象也不同了:

697960108
943010986
false
com.nmys.story.interview.copy_interview.Student@299a06ac
com.nmys.story.interview.copy_interview.Student@383534aa
com.nmys.story.interview.copy_interview.Active@6bc168e5
com.nmys.story.interview.copy_interview.Active@7b3300e5

可以得出深拷貝的幾點結(jié)論:

  • 深拷貝是完全創(chuàng)建一個新的對象
  • 深拷貝也會將原始對象中的引用對象重新復(fù)制一份

總結(jié)

  1. 一定要實現(xiàn)Cloneable接口具则。
  2. 重寫clone()方法即纲,注意:默認(rèn)是淺拷貝,這里需要將引用類型進(jìn)行深拷貝處乡洼。
  3. 特殊:String類雖然是引用類型崇裁,但是是final類匕坯,同時也有字符串常量池的存在束昵,不必進(jìn)行處理。
  4. 深拷貝可以通過上面所說的clone方法實現(xiàn)葛峻,還可以通過序列化來實現(xiàn)锹雏。
  5. 當(dāng)時寫測試用例的時候,我這里用了lombok的注解@Data术奖,為的就是不用手寫get礁遵、set方法了,但測試的時候采记,發(fā)現(xiàn)clone出來的對象的hashcode是一樣的佣耐,原因是lombok在為我們生成get、set的同時唧龄,toString兼砖、hashCode、equals等方法都替我們重寫了既棺,導(dǎo)致clone出來的類雖然 ==false 讽挟,但是hashCode卻一樣,建議還是手動寫比較好丸冕。
  6. 最后再總結(jié)下耽梅,假設(shè),A 類中引用了 B 類胖烛,B 類中引用了 C 類眼姐,對象分別對應(yīng) a诅迷,b,c众旗,淺拷貝 a 的結(jié)果 a1竟贯,b,c逝钥。深拷貝 a 的結(jié)果 a1屑那,b1,c1艘款。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末持际,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子哗咆,更是在濱河造成了極大的恐慌蜘欲,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晌柬,死亡現(xiàn)場離奇詭異姥份,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)年碘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門澈歉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人屿衅,你說我怎么就攤上這事埃难。” “怎么了涤久?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵涡尘,是天一觀的道長。 經(jīng)常有香客問我响迂,道長考抄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任蔗彤,我火速辦了婚禮川梅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘幕与。我一直安慰自己挑势,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布啦鸣。 她就那樣靜靜地躺著潮饱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诫给。 梳的紋絲不亂的頭發(fā)上香拉,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天啦扬,我揣著相機(jī)與錄音,去河邊找鬼凫碌。 笑死扑毡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盛险。 我是一名探鬼主播瞄摊,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼苦掘!你這毒婦竟也來了换帜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤鹤啡,失蹤者是張志新(化名)和其女友劉穎惯驼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體递瑰,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡祟牲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了抖部。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片说贝。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖您朽,靈堂內(nèi)的尸體忽然破棺而出狂丝,到底是詐尸還是另有隱情换淆,我是刑警寧澤哗总,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站倍试,受9級特大地震影響讯屈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜县习,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一涮母、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧躁愿,春花似錦叛本、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至逸雹,卻和暖如春营搅,著一層夾襖步出監(jiān)牢的瞬間云挟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工转质, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留园欣,地道東北人。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓休蟹,卻偏偏與公主長得像沸枯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子赂弓,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,697評論 2 351