日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java设计模式百例(番外) - Java的clone

發(fā)布時間:2025/3/20 java 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java设计模式百例(番外) - Java的clone 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文源碼見:https://github.com/get-set/get-designpatterns/tree/master/prototype

本文是為下一篇“Java設(shè)計模式百例 - 原型模式”做鋪墊,討論一下Java中的對象克隆。本文內(nèi)容綜合了《Effective Java》、《Java與模式》以及其他網(wǎng)上相關(guān)資料,希望能夠?qū)δ灿兴鶐椭?/p>

Java中,對象的創(chuàng)建除了用new關(guān)鍵字,還可以使用既有對象的clone()方法來復(fù)制自身達(dá)到創(chuàng)建一個新對象的目的。

關(guān)于對象克隆,Java中有通用約定:

通用約定1: x.clone() != x 必須為真。

對象克隆與引用的復(fù)制是有本質(zhì)區(qū)別的,區(qū)別就在于x.clone()后產(chǎn)生的對象與x并不位于同一塊內(nèi)存上,兩者是獨立的,修改兩者任何一方的成員都不會導(dǎo)致另一方發(fā)生變化。就像克隆羊多利(Dolly)不會因為其“基因母親”(很遺憾,它沒有名字,我們暫且諧音基因,就叫Jane吧)受傷或死亡而受傷或死亡。代碼舉例:

Sheep.java

public?class?Sheep?implements?Cloneable?{private?String?name;????//名字private?int?age;????????//年齡private?String?breed;???//品種private?EarTag?earTag;??//耳牌//?構(gòu)造方法public?Sheep(String?name,?int?age,?String?breed,?EarTag?earTag)?{this.name?=?name;this.age?=?age;this.breed?=?breed;this.earTag?=?earTag;}//?getters?&?setters@Overridepublic?Sheep?clone()?throws?CloneNotSupportedException?{return?(Sheep)?super.clone();}@Overridepublic?String?toString()?{return?this.name?+?"是一只"?+?this.age?+?"歲的"?+?this.breed?+?",?它的"?+?this.earTag.getColor()?+?"色耳牌上寫著"?+?this.earTag.getId()?+?"號。";} }

每只羊身上有個耳牌:

EarTag.java

public?class?EarTag?implements?Cloneable?{private?int?id;?????????//耳牌編號private?String?color;???//耳牌顏色//?構(gòu)造方法public?EarTag(int?id,?String?color)?{this.id?=?id;this.color?=?color;}//?getters?&?setters }

注意,

  • 以上兩個類均需要實現(xiàn)Cloneable接口,否則執(zhí)行clone()方法會報CloneNotSupportedException異常。

  • 若某個類允許其對象可以克隆,那么需要重寫clone()方法,并且聲明為public的,因為Object的clone()方法是protected,無法被非子類和不在當(dāng)前包的其他類或?qū)ο笳{(diào)用。

  • 派生類的clone()方法中,要調(diào)用super.clone(),以便能夠最終調(diào)用到Object.clone(),后者是個native方法,效率更高。

  • 克隆過程如下:

    Sheep?jane?=?new?Sheep("簡",?5,?"多塞特白面綿羊",?new?EarTag(12345,?"×××")); System.out.println(jane); Sheep?dolly?=?jane.clone(); System.out.println("克隆后..."); dolly.setName("多利"); dolly.getEarTag().setId(12346); System.out.println(dolly);

    輸出結(jié)果為:

    簡是一只5歲的多塞特白面綿羊,?它的×××色耳牌上寫著12345號。 克隆后... 多利是一只5歲的多塞特白面綿羊,?它的×××色耳牌上寫著12346號。

    仿佛很完美,所有的信息都克隆過來了,但是,我們在看一下jane這個對象(最后增加兩個輸出):

    System.out.println(jane); System.out.println(jane.getEarTag()?==?dolly.getEarTag());

    輸出結(jié)果為:

    簡是一只5歲的多塞特白面綿羊,?它的×××色耳牌上寫著12346號。 true

    這就不對了,簡的耳牌號也變了,而且我們看到兩只羊的耳牌是”==“的,也就是jane.earTag和dolly.earTag指向的是同一個對象。這在現(xiàn)實中是毫無道理的。可見,earTag這個成員變量是引用復(fù)制。

    淺復(fù)制

    上邊例子中,最終調(diào)用到的Object.clone()就是淺復(fù)制。所謂淺復(fù)制,可以理解為只復(fù)制成員變量的”值“。

  • 對于原生類型,其”值“就是實實在在的值,比如int age,是直接復(fù)制的;

  • 對于引用類型,其”值“就是引用本身,比如EarTag earTag,引用原來指向的是”×××編號為12345的牌子“,引用復(fù)制過來仍然是指向同樣的牌子,所以只是復(fù)制的值,而并未復(fù)制引用指向的對象;

  • (補充)對于引用類型,如果引用本身指向的是不可變類,比如String、Integer等,引用指向的對象內(nèi)容是不可變的,一旦需要改變,其實就是從新new了一個對象,因此可以認(rèn)為復(fù)制了引用指向的對象。其效果”看起來“和原生類型的待遇是一樣的。

  • 總結(jié)來說,被復(fù)制對象的所有原生類型變量和不可變類的引用都復(fù)制與原來的對象相同的值,而所有的對其他對象(不包含不可變類的對象)的引用仍然指向原來的對象。

    深復(fù)制

    相對于淺復(fù)制,更進(jìn)一步,深拷貝把要復(fù)制的對象所引用的對象都復(fù)制一遍。

    實現(xiàn)深復(fù)制有兩種方式。一種是繼續(xù)利用clone()方法,另一種是利用對象序列化。

    對于第一種方法,進(jìn)一步手動將指向可變對象的引用再復(fù)制一遍即可。比如對于Sheep我們增加deepClone()方法,在該方法中明確將EarTag對象也復(fù)制一下。因此EarTag也需要重寫clone()方法。

    Sheep.java增加deepClone()方法

    public?Sheep?deepClone()?throws?CloneNotSupportedException?{Sheep?s?=?(Sheep)super.clone();s.setEarTag(s.getEarTag().clone());return?s; }

    EarTag.java增加clone()方法,別忘了實現(xiàn)Cloneable接口

    @Override public?EarTag?clone()?throws?CloneNotSupportedException?{return?(EarTag)?super.clone(); }

    這時候再測試一遍看輸出:

    簡是一只5歲的多塞特白面綿羊,?它的×××色耳牌上寫著12345號。 克隆后... 多利是一只6歲的多塞特白面綿羊,?它的×××色耳牌上寫著12346號。 簡是一只5歲的多塞特白面綿羊,?它的×××色耳牌上寫著12345號。 false

    可見,EarTag對象也被克隆了。

    這時,其實還需要注意一個問題,我們這個例子中,EarTag的對象沒有指向其他對象的引用,假設(shè)有的話,是否要調(diào)用EarTag的deepClone()方法呢,如果是一個引用鏈,深度復(fù)制要達(dá)到什么樣的深度呢?是否有循環(huán)引用呢(比如EarTag中又有對Sheep的引用)?這都是在具體的使用過程中需要謹(jǐn)慎考慮的。

    第二種方法是通過對象序列化來實現(xiàn)對象的深克隆。在Sheep.java中增加如下方法:

    public?Sheep?serializedClone()?throws?IOException,?ClassNotFoundException?{ByteArrayOutputStream?bao?=?new?ByteArrayOutputStream();ObjectOutputStream?oo?=?new?ObjectOutputStream(bao);oo.writeObject(this);ByteArrayInputStream?bai?=?new?ByteArrayInputStream(bao.toByteArray());ObjectInputStream?oi?=?new?ObjectInputStream(bai);return?(Sheep)?oi.readObject(); }

    注意的是,Sheep和EarTag都需要實現(xiàn)Serializable接口,以便打開對序列化的支持。

    測試一下:

    Sheep?jane?=?new?Sheep("簡",?5,?"多塞特白面綿羊",?new?EarTag(12345,?"×××")); System.out.println(jane); Sheep?dolly?=?jane.serializedClone(); System.out.println("克隆后..."); dolly.setName("多利"); dolly.setAge(6); dolly.getEarTag().setId(12346); System.out.println(dolly);System.out.println(jane); System.out.println(jane.getEarTag()?==?dolly.getEarTag());

    輸出如下:

    簡是一只5歲的多塞特白面綿羊,?它的×××色耳牌上寫著12345號。 克隆后... 多利是一只6歲的多塞特白面綿羊,?它的×××色耳牌上寫著12346號。 簡是一只5歲的多塞特白面綿羊,?它的×××色耳牌上寫著12345號。 false

    可見也確實實現(xiàn)了深克隆。

    通用約定2: x.clone().getClass() == x.getClass() 必須為真。

    指的是克隆后的對象其類型是一致的。這一點沒有問題,及時在有繼承關(guān)系的情況下。

    ClassA.java

    public?class?ClassA?implements?Cloneable?{public?int?getA()?{return?a;}public?void?setA(int?a)?{this.a?=?a;}private?int?a;@Overridepublic?ClassA?clone()?throws?CloneNotSupportedException?{return?(ClassA)?super.clone();} }

    ClassB.java(繼承ClassA)

    public?class?ClassB?extends?ClassA?{private?String?b;public?String?getB()?{return?b;}public?void?setB(String?b)?{this.b?=?b;}public?void?test()?{System.out.println(super.getClass().getCanonicalName());} }

    測試一下:

    ClassB?b?=?new?ClassB(); b.setA(1); b.setB("b"); ClassB?b1?=?(ClassB)?b.clone(); System.out.println(b1.getB());

    結(jié)果為:

    b

    可見,即使子類沒有重寫clone()方法,只要其各層父類中有重新了public的clone()方法的,那么clone()方法都能正確克隆調(diào)起該方法的對象,且類型正確。話說回來,畢竟clone()的動作最終都是源于Object的那個native方法的。

    通用約定3: x.clone().equals(x)為真

    這一條并非強制約束,但盡量保證做到。因為從一般認(rèn)識上來講,克隆的兩個對象雖然是不相等(==)的,但應(yīng)該是相同(equal)的。

    重寫Sheep.java和EarTag.java的equals()方法:

    Sheep.java

    ????@Overridepublic?boolean?equals(Object?obj)?{if?(obj?==?this)return?true;if?(!(obj?instanceof?Sheep))return?false;Sheep?s?=?(Sheep)?obj;return?s.name.equals(this.name)?&&s.age?==?this.age?&&s.breed.equals(this.breed)?&&s.earTag.equals(this.earTag);}

    EarTag.java

    ????@Overridepublic?boolean?equals(Object?obj)?{if?(obj?==?this)return?true;if?(!(obj?instanceof?Sheep))return?false;Sheep?s?=?(Sheep)?obj;return?s.name.equals(this.name)?&&s.age?==?this.age?&&s.breed.equals(this.breed)?&&s.earTag.equals(this.earTag);}

    測試一下:

    Sheep?jane?=?new?Sheep("簡",?5,?"多塞特白面綿羊",?new?EarTag(12345,?"×××")); Sheep?dolly?=?jane.serializedClone(); System.out.println("克隆后..."); System.out.println(jane.equals(dolly));

    輸出為true,表示兩個對象是相同的。

    總結(jié)

    最后,我們總結(jié)一下,實現(xiàn)clone的方法:?
    1)在派生類中實現(xiàn)Cloneable借口;?
    2)在派生類中覆蓋基類的clone方法,聲明為public;?
    3)在派生類的clone方法中,調(diào)用super.clone();?
    4)若要深克隆對象,則需要增加對引用為非不可變對象的克隆。


    轉(zhuǎn)載于:https://blog.51cto.com/liukang/1982920

    總結(jié)

    以上是生活随笔為你收集整理的Java设计模式百例(番外) - Java的clone的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 久草麻豆 | 国产chinese男男gaygay视频 | 伊人自拍 | hd性videos意大利精品 | 欧美一区二区视频免费观看 | 精品一区二区三区人妻 | 免费av高清| 国产夫妻性生活 | 国产精品毛片在线 | 亚洲图片在线 | 日韩女同一区二区三区 | 污视频在线免费观看 | 天天操天天操天天 | 国产又粗又猛又黄又爽的视频 | 一本之道高清无码视频 | 免费一级一片 | 成年人午夜视频 | 小泽玛利亚一区二区三区 | 天天爱天天干天天操 | 欧美成年人 | 午夜av电影在线观看 | 天堂素人约啪 | 伊是香蕉大人久久 | 成人二区三区 | 精品国产无码AV | 一本一道久久a久久精品综合 | 伊人55| 久久国色| 亚洲情热 | 在线观看麻豆 | 日本资源在线 | 久久精品视频7 | 性视频播放免费视频 | 色七七桃花综合影院 | 毛片网站视频 | 成年人拍拍视频 | 国产chinesehd精品露脸 | 在线www| 91视频在线免费观看 | 成人午夜免费观看 | china国产乱xxxxx绿帽 | 自拍天堂 | 杨贵妃颤抖双乳呻吟求欢小说 | 国产女人18毛片水18精品 | 水蜜桃影库 | 国产一区二区视频在线免费观看 | 91亚瑟视频 | 狠狠gao| 精品一区二区视频 | 操操日日 | a天堂在线资源 | 美女福利片 | 久久91亚洲精品中文字幕奶水 | 色开心 | 激情黄色小说网站 | 欧美人妻一区二区三区 | 福利一区在线观看 | 狠狠干网址 | 美女视频黄色免费 | 精品人妻一区二区乱码 | 日韩视频免费观看 | 黄色一级大片在线观看 | 欧美三级午夜理伦三级中视频 | 欧洲午夜视频 | 一区二区在线观看视频 | 日韩h在线观看 | 99久久视频 | 亚洲欧美强伦一区二区 | 13日本xxxxxⅹxxx20| 亚洲超碰av | 爆操白虎逼 | 日本泡妞xxxx免费视频软件 | 日本亚洲天堂 | 91看篇| 三区在线视频 | 肉色丝袜脚交一区二区 | 亚洲欧美中日韩 | 亚洲夜夜夜 | 久成人| 午夜伦视频 | 亚洲色图 一区二区 | 一道本在线播放 | 黄色一级片在线播放 | 国产激情小视频 | 91成人在线视频 | 亚洲精品v | 久久国产色| 超碰人人搞 | 欧美xxxx性xxxxx高清 | 精品一区二区三区精华液 | 日日插插 | 熟睡人妻被讨厌的公侵犯 | 久色福利 | 免费网站污 | 亚洲校园激情 | 欧洲金发美女大战黑人 | 91在线视频 | 97xxxxx| 亚洲在线天堂 |