成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

從clone方法到復(fù)制構(gòu)造函數(shù)

孫吉亮 / 2452人閱讀

摘要:有一些設(shè)計(jì)缺陷,其中最大的一個(gè)是接口沒有方法。這基本上就是你用復(fù)制構(gòu)造函數(shù)做的事情。復(fù)制構(gòu)造方法有幾個(gè)優(yōu)點(diǎn),我在本書中有討論。的方法是非常棘手的。它創(chuàng)建一個(gè)對(duì)象而不調(diào)用構(gòu)造函數(shù)。無法保證它保留構(gòu)造函數(shù)建立的不變量。

前言

在Java API中,可以通過實(shí)現(xiàn)Cloneable接口并重寫clone方法實(shí)現(xiàn)克隆,但Java設(shè)計(jì)者否定了使用clone創(chuàng)建新對(duì)象的方法.

1. clone方法實(shí)現(xiàn)對(duì)象的復(fù)制

在Java API中,如果被克隆的對(duì)象成員變量有對(duì)象變量,則對(duì)象變量也需要實(shí)現(xiàn)Cloneable接口,并重新給新的父類賦值,例如:

1.創(chuàng)建一個(gè)對(duì)象,其存在對(duì)象類型的成員變量childClone

class ParentsClone implements Cloneable {

    public int id;
    public ChildClone childClone;

    public ParentsClone(int id) {
        this.id = id;
    }

    public ParentsClone(int id, ChildClone childClone) {
        this.id = id;
        this.childClone = childClone;
    }

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

2.因此ChildClone也需要實(shí)現(xiàn)Cloneable:

class ChildClone implements Cloneable {
    public String name;

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

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

3.所以要做到真正的clone需要按照如下調(diào)用順序操作:

public class ParentClone implements Cloneable {

    public static void main(String[] args) throws CloneNotSupportedException {
        ParentsClone p1 = new ParentsClone(1, new ChildClone("HAHA"));
        ParentsClone p2 = (ParentsClone) p1.clone();
        p2.childClone = (ChildClone) p1.childClone.clone();

        System.out.println("p1 HashCode: " + p1.hashCode() + "  p1.child HashCode: " + p1.childClone.hashCode());
        System.out.println("p2 HashCode: " + p2.hashCode() + "  p2.child HashCode: " + p2.childClone.hashCode());
    }
}
//output:
/**
* p1 HashCode: 1163157884  p1.child HashCode: 1956725890
* p2 HashCode: 356573597  p2.child HashCode: 1735600054
*/

4.如此便完成了java對(duì)象的真正clone.但是java開發(fā)者并不建議這樣做.

2. 和JAVA開發(fā)者對(duì)話

Bill Venners: 在你的書中,你建議使用復(fù)制構(gòu)造函數(shù)而不是實(shí)現(xiàn)Cloneable和編寫clone。你能詳細(xì)說明嗎?

Josh Bloch:如果你已經(jīng)閱讀了我的書中關(guān)于克隆的章節(jié),特別是如果你看得仔細(xì)的話,你就會(huì)知道我認(rèn)為克隆已經(jīng)完全壞掉的東西。有一些設(shè)計(jì)缺陷,其中最大的一個(gè)是 Cloneable 接口沒有 clone方法。這意味著它根本不起作用:實(shí)現(xiàn)了 Cloneable 接口并不說明你可以用它做什么。相反,它說明了內(nèi)部可能做些什么。它說如果通過super.clone 反復(fù)調(diào)用它最終調(diào)用 Object 的 clone 方法,這個(gè)方法將返回原始的屬性副本。

但它沒有說明你可以用一個(gè)實(shí)現(xiàn) Cloneable 接口的對(duì)象做什么,這意味著你不能做多態(tài) clone 操作。如果我有一個(gè) Cloneable 數(shù)組,你會(huì)認(rèn)為我可以運(yùn)行該數(shù)組并克隆每個(gè)元素以制作數(shù)組的深層副本,但不能。你不能強(qiáng)制轉(zhuǎn)換對(duì)象為 Cloneable 接口并調(diào)用 clone 方法,因?yàn)?Cloneable 沒有public clone 方法,Object 類也沒有。如果您嘗試強(qiáng)制轉(zhuǎn)換 Cloneable 并調(diào)用該 clone 方法,編譯器會(huì)說您正在嘗試在對(duì)象上調(diào)用受保護(hù)的clone方法。

事實(shí)的真相是,您不通過實(shí)施 Cloneable 和提供 clone 除復(fù)制能力之外的公共方法為您的客戶提供任何能力。如果您提供具有不同名稱的copy操作, 怎么也不次于去實(shí)現(xiàn) Cloneable 接口。這基本上就是你用復(fù)制構(gòu)造函數(shù)做的事情。復(fù)制構(gòu)造方法有幾個(gè)優(yōu)點(diǎn),我在本書中有討論。一個(gè)很大的優(yōu)點(diǎn)是可以使副本具有與原始副本不同的實(shí)現(xiàn)。例如,您可以將一個(gè) LinkedList 復(fù)制到 ArrayList。

Object 的 clone 方法是非常棘手的。它基于屬性復(fù)制,而且是“超語言”。它創(chuàng)建一個(gè)對(duì)象而不調(diào)用構(gòu)造函數(shù)。無法保證它保留構(gòu)造函數(shù)建立的不變量。多年來,在Sun內(nèi)外存在許多錯(cuò)誤,這源于這樣一個(gè)事實(shí),即如果你只是super.clone 反復(fù)調(diào)用鏈直到你克隆了一個(gè)對(duì)象,那么你就擁有了一個(gè)淺層的對(duì)象副本??寺⊥ǔEc正在克隆的對(duì)象共享狀態(tài)。如果該狀態(tài)是可變的,則您沒有兩個(gè)獨(dú)立的對(duì)象。如果您修改一個(gè),另一個(gè)也會(huì)更改。突然之間,你會(huì)得到隨機(jī)行為。

我使用的東西很少實(shí)現(xiàn) Cloneable。我經(jīng)常提供實(shí)現(xiàn)類的 clone 公共方法,僅是因?yàn)槿藗兤谕小N覜]有抽象類實(shí)現(xiàn) Cloneable,也沒有接口擴(kuò)展它,因?yàn)槲也粫?huì)將實(shí)現(xiàn)的負(fù)擔(dān) Cloneable 放在擴(kuò)展(或?qū)崿F(xiàn))抽象類(或接口)的所有類上。這是一個(gè)真正的負(fù)擔(dān),幾乎沒有什么好處。

Doug Lea 走得更遠(yuǎn)。他告訴我 clone 除了復(fù)制數(shù)組之外他不再使用了。您應(yīng)該使用 clone 復(fù)制數(shù)組,因?yàn)檫@通常是最快的方法。但 Doug 的類根本就不再實(shí)施 Cloneable了。他放棄了。而且我認(rèn)為這并非不合理。

這是一個(gè)恥辱, Cloneable 接口壞掉了,但它發(fā)生了。最初的 Java API在緊迫的期限內(nèi)完成,以滿足市場(chǎng)窗口收緊的需求。最初的 Java 團(tuán)隊(duì)做了不可思議的工作,但并非所有的 API 都是完美的。 Cloneable 是一個(gè)弱點(diǎn),我認(rèn)為人們應(yīng)該意識(shí)到它的局限性。
傳送門:<復(fù)制構(gòu)造函數(shù)與克隆>英文原版

3. 總結(jié)Java開發(fā)者的話

設(shè)計(jì)缺陷, Cloneable 接口沒有 clone方法.

調(diào)用的是Object的clone方法,返回原始的屬性副本.

clone方法返回淺層的對(duì)象副本.

應(yīng)該使用 clone 復(fù)制數(shù),因?yàn)橥ǔK俣茸羁?.{具體使用: int[] newArrays=(int[])oldArrays.clone() }

復(fù)制構(gòu)造方法的優(yōu)點(diǎn):副本具有與原始副本不同的實(shí)現(xiàn).

4. 復(fù)制構(gòu)造函數(shù)

java開發(fā)者不建議我們使用clone方法,從而轉(zhuǎn)向靈活的構(gòu)造函數(shù)實(shí)現(xiàn)方法.
1.新寫兩個(gè)類,分別兩個(gè)構(gòu)造函數(shù),關(guān)注第二個(gè)構(gòu)造函數(shù),參數(shù)為當(dāng)前類的對(duì)象實(shí)例.

class Parents {

    public int id;
    public Child child;

    public Parents(int id, Child child) {
        this.id = id;
        this.child = child;
    }
    //實(shí)現(xiàn)對(duì)象的復(fù)制
    public Parents(Parents parents) {
        id = parents.id;
        child = new Child(parents.child);
    }
}


class Child {
    public String name;

    public Child(String name) {
        this.name = name;
    }
    //實(shí)現(xiàn)對(duì)象的復(fù)制
    public Child(Child child) {
        name = child.name;
    }
}

2.測(cè)試:

public static void main(String[] args) throws CloneNotSupportedException {

       Parents p1=new Parents(1,new Child("HAHA"));
       Parents p2=new Parents(p1);

       System.out.println("p1 HashCode: " + p1.hashCode() + "  p1.child HashCode: " + p1.child.hashCode());
       System.out.println("p2 HashCode: " + p2.hashCode() + "  p2.child HashCode: " + p2.child.hashCode());

       //output
       /**
        * p1 HashCode: 1163157884  p1.child HashCode: 1956725890
        * p2 HashCode: 356573597  p2.child HashCode: 1735600054
        */

   }
結(jié)語

以上便是筆者對(duì)放棄clone,使用構(gòu)造方法創(chuàng)建新對(duì)象的整理.以后的程序中盡量還是多用復(fù)制構(gòu)造函數(shù)的方法.若有不足,敬請(qǐng)指正.

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/73949.html

相關(guān)文章

  • Java 作者談克隆方法的實(shí)現(xiàn)

    摘要:不合規(guī)的代碼示例合規(guī)解決方案參閱復(fù)制構(gòu)造函數(shù)與克隆也可以參閱應(yīng)該實(shí)現(xiàn)克隆覆蓋的類應(yīng)為并調(diào)用下面為引文翻譯談設(shè)計(jì)與作者的對(duì)話,作者首次在上發(fā)表,年月日復(fù)制構(gòu)造函數(shù)與克隆在你的書中,你建議使用復(fù)制構(gòu)造函數(shù)而不是實(shí)現(xiàn)和編寫。 今天在用 sonar 審核代碼, 偶然看到下面的提示:showImg(https://segmentfault.com/img/bVbqioZ?w=858&h=116)...

    gaomysion 評(píng)論0 收藏0
  • [譯] 為什么原型繼承很重要

    摘要:使用構(gòu)造函數(shù)的原型繼承相比使用原型的原型繼承更加復(fù)雜,我們先看看使用原型的原型繼承上面的代碼很容易理解。相反的,使用構(gòu)造函數(shù)的原型繼承像下面這樣當(dāng)然,構(gòu)造函數(shù)的方式更簡(jiǎn)單。 五天之前我寫了一個(gè)關(guān)于ES6標(biāo)準(zhǔn)中Class的文章。在里面我介紹了如何用現(xiàn)有的Javascript來模擬類并且介紹了ES6中類的用法,其實(shí)它只是一個(gè)語法糖。感謝Om Shakar以及Javascript Room中...

    xiao7cn 評(píng)論0 收藏0
  • 搞定PHP面試 - PHP魔術(shù)方法知識(shí)點(diǎn)整理

    摘要:魔術(shù)方法知識(shí)點(diǎn)整理代碼使用語法編寫一構(gòu)造函數(shù)和析構(gòu)函數(shù)構(gòu)造函數(shù)具有構(gòu)造函數(shù)的類會(huì)在每次創(chuàng)建新對(duì)象時(shí)先調(diào)用此方法,所以非常適合在使用對(duì)象之前做一些初始化工作。在析構(gòu)函數(shù)中調(diào)用將會(huì)中止其余關(guān)閉操作的運(yùn)行。析構(gòu)函數(shù)中拋異常會(huì)導(dǎo)致致命錯(cuò)誤。 PHP魔術(shù)方法知識(shí)點(diǎn)整理 代碼使用PHP7.2語法編寫 一、構(gòu)造函數(shù)和析構(gòu)函數(shù) __construct() 構(gòu)造函數(shù) __construct ([ mi...

    付永剛 評(píng)論0 收藏0
  • 設(shè)計(jì)模式之原型模式

    摘要:但是這種復(fù)制技術(shù)在的世界里早已出現(xiàn),就是原型模式什么是原型模式用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過拷貝這些原型創(chuàng)建新的對(duì)象類圖原型模式是設(shè)計(jì)模式中最簡(jiǎn)單的,沒有之一。 前言 在現(xiàn)實(shí)世界中,我們通常會(huì)感覺到分身乏術(shù)。要是自己有分身那該多好啊,一個(gè)用來工作,一個(gè)用來看電視,一個(gè)用來玩游戲(無意中透露了自己?jiǎn)紊砉返纳矸?。-),其實(shí)就是克隆,這種技術(shù)存在著很大的弊端,所以現(xiàn)在是禁止使用的。...

    jsyzchen 評(píng)論0 收藏0
  • JavaScript 原型鏈

    摘要:命令通過構(gòu)造函數(shù)新建實(shí)例對(duì)象,實(shí)質(zhì)就是將實(shí)例對(duì)象的原型,指向構(gòu)造函數(shù)的屬性,然后在實(shí)例對(duì)象上執(zhí)行構(gòu)造函數(shù)。 大部分面向?qū)ο蟮木幊陶Z言,都是以類(class)作為對(duì)象體系的語法基礎(chǔ)。JavaScript語言中是沒有class的概念的(ES6之前,ES6中雖然提供了class的寫法,但實(shí)現(xiàn)原理并不是傳統(tǒng)的類class概念,僅僅是一種寫法), 但是它依舊可以實(shí)現(xiàn)面向?qū)ο蟮木幊蹋@就是通過Ja...

    verano 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<