Java 編程思想筆記:Learn 5

繼承和組合的使用時機

到底是該用組合還是繼承捞镰,一個最清晰的辦法就是判斷是否需要從新類向基類進行向上轉(zhuǎn)型闸与。如果必須向上轉(zhuǎn)型,則繼承是必要的岸售。

什么時候践樱,一定會用到向上轉(zhuǎn)型呢?當(dāng)然是子類在定義時需要調(diào)用父類方法的時候凸丸。

另外拷邢,子類與父類的關(guān)系是 is-a 的關(guān)系。

final 數(shù)據(jù)

final 修飾常量時屎慢,表示這個常量是不改變的瞭稼。一個既是 static 又是 final 的域只占據(jù)一段不能改變的存儲空間。

final 修飾引用時腻惠,表示 final 使得引用恒定不變环肘,一旦引用被初始化指向一個對象,就無法再把它改為指向另外一個對象集灌。
然而悔雹,對象其自身卻是可以被修改的。這一限制同樣適用于數(shù)組,它也是對象腌零。

public class A{
    final int[] a0 = {1};
}

class TestA{

    void test(){
        A a = new A();
        a.a0[0]++;
    }
}
空白 final

Java 允許在聲明變量但未賦值的情況下用final修飾梯找,但是 final 修飾的變量必須在 constructor 中被賦值。
這樣的做法益涧,保證了靈活性初肉。

class Poppet{
    private int i;
    Poppet(int x){
        i = x;
    }
}

public class BlankFinal{
    private final int j;
    private final Poppet poppet;

    public BlankFinal(){
        j = 0;
        poppet = new Poppet(j);
    }
    
    public BlankFinal(int x){
        j = x;
        poppet = new Poppet(x);
    }
}
final 修飾參數(shù)

final 也可以用來修飾參數(shù),表示參數(shù)不可以被更改饰躲。這一特性主要是用來向匿名內(nèi)部類中傳遞數(shù)據(jù)牙咏。

class Gizmo{
    public void spin(){}
}

public class FinalArguments{
    void with(final Gizmo g){
        // g = new Gizmo() 這種寫法是錯誤的,因為 g 是 final,這樣的寫法保證了 g 只具有只讀屬性嘹裂。
    }
}
final 方法

使用 final 方法有兩個原因妄壶,第一個原因是把方法鎖定,以防止任何繼承類修改它的含義寄狼。
這是出于設(shè)計的考慮丁寄,想要確保繼承在子類中方法不變,并且不會被覆蓋泊愧。
第二個原因是伊磺,早期發(fā)現(xiàn) final 修飾的方法會更快,現(xiàn)在已經(jīng)不需要了删咱。

final 和 private 關(guān)鍵字

類中所有的 private 方法都隱式指定為 final的屑埋。由于無法取用 private 方法,也就無法覆蓋它痰滋。

final 類

當(dāng)將某個類的整體定義為 final 時摘能,表明該類不允許繼承

7.9 初始化及類的加載

在 Beetle 上運行 Java 時,所發(fā)生的第一件事就是試圖訪問 Beetle.main() (一個 static 方法)敲街,

于是加載器開始啟動并找出 Bettle 類的編譯代碼(在名為 Bettle.class 的文件之中)团搞。在對它進行加載

的過程中,編譯器注意到它有一個基類(由關(guān)鍵字 extends 得知的)多艇,于是它繼續(xù)進行加載逻恐。

對象中所有的基本類型都會被設(shè)為默認(rèn)值,對象引用被設(shè)為 null ——這是由將對象內(nèi)存設(shè)為二進制零值而一舉生成的峻黍。

然后复隆,基類的構(gòu)造器會被調(diào)用。在本例中奸披,它是被自動調(diào)用的昏名。但也可以用 super 來指定對基類構(gòu)造器的調(diào)用。

在開始設(shè)計時阵面,一般優(yōu)先選擇使用組合,只有必要時才選擇繼承。因為組合更具有靈活性样刷。此外仑扑,通過對成員類型使用

繼承技術(shù)的添加技巧,可以在運行時改變那些成員對象的類型和行為置鼻。

多態(tài)

將一個方法調(diào)用同一個主體關(guān)聯(lián)起來被成為綁定镇饮,若程序執(zhí)行前進行綁定,叫做前期綁定箕母。

后期綁定储藐,也叫動態(tài)綁定或運行時綁定,在運行時根據(jù)對象的類型進行綁定嘶是。Java 中除了 static 和 final 方法钙勃,其他所有的方法

都是后期綁定的。為什么要講某個方法聲明為 final 呢聂喇?它可以防止其他人覆蓋該方法辖源,可以有效地關(guān)閉動態(tài)綁定,告訴編譯器不需要對其進行動態(tài)綁定希太。

多態(tài)的缺陷

  1. 私有方法無法重載
public class PrivateOverride {
    private void f(){
        System.out.println("private f()");
    }
    
    public static void main(String[] args){
        PrivateOverride po = new Derived();
        po.f();
    }
}

class Derived extends PrivateOverride {
    public void f(){
        System.out.println("public f()");
    }
}
  1. 只有普通的方法調(diào)用可以是多態(tài)的

只有普通的方法調(diào)用可以是多態(tài)的克饶,如果直接訪問某個屬性,那么這個訪問將在編譯期間就進行解析

class Super{
    public int filed = 0;
    public int getFiled(){
        return filed;
    }
}

class Sub extends Super{
    public int filed = 1;
    public int getFiled(){
        return field;
    }
    public int getSuperField(){
        return super.field;
    }
}

public class FieldAccess{
    public static void main(String[] args){
        Super sup = new Sub();
        // 對屬性的訪問是在編譯期間就確定的
        System.out.println("sup.field = " + sup.field + 
        ", sup.getField() = " + sup.getField());
        Sub sub = new Sub();
        System.out.println("sub.field = " + 
        sub.field + ", sub.getFiled() = " + 
        sub.getField() + 
        sub.getSuperField());
    }
}

8.3 構(gòu)造器和多態(tài)

  1. 調(diào)用基類構(gòu)造器誊辉,這個步驟會反復(fù)地不斷遞歸下去矾湃。首先是構(gòu)造這種層次的根,然后是下一層導(dǎo)出類堕澄,直到最低層的導(dǎo)出類洲尊。
  2. 按照聲明順序調(diào)用成員的初始化方法
  3. 調(diào)用導(dǎo)出類構(gòu)造器的主體
package com.zzjack.wxorder.javathought;


class Meal{
    Meal(){
        System.out.println("Meal()");
    }
}

class Bread{
    Bread(){
        System.out.println("Bread()");
    }
}

class Cheese{
    Cheese(){
        System.out.println("Cheese()");
    }
}

class Lettuce{
    Lettuce(){
        System.out.println("Lettuce()");
    }
}

class Lunch extends Meal{
    Lunch(){
        System.out.println("Lunch()");
    }
}


class PortableLunch extends Lunch{
    PortableLunch(){
        System.out.println("PortableLunch");
    }
}

public class Sandwich extends PortableLunch{
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Lettuce l = new Lettuce();
    public Sandwich(){
        System.out.println("Sanwich()");
    }
    public static void main(String[] args){
        new Sandwich();
    }
}

8.3.3 構(gòu)造器內(nèi)部的多態(tài)方法的行為

  1. 在其他任何事物發(fā)生之前,將分配給對象的存儲空間初始化成二進制的零奈偏。

  2. 如前所述的那樣調(diào)用基類構(gòu)造器坞嘀。此時,調(diào)用被覆蓋后的 draw() 方法(要在調(diào)用 RoundGlyph 構(gòu)造器之前調(diào)用)惊来,
    由于步驟1的緣故丽涩,我們此時會發(fā)現(xiàn) radius 的值為 0

  3. 按照聲明的順序調(diào)用成員的初始化方法

  4. 調(diào)用導(dǎo)出類的構(gòu)造器主體

編寫構(gòu)造器時有一條有效的準(zhǔn)則:用盡可能簡單的方法使對象進入正常狀態(tài),如果可以的話裁蚁,避免調(diào)用其它方法矢渊。在構(gòu)造器內(nèi)

唯一能夠安全調(diào)用的那些方法是基類中的 final 方法。final 方法不能被覆蓋枉证,因此也就不會出現(xiàn)上述令人驚訝的問題矮男。

8.4 協(xié)變返回類型

在設(shè)計時,組合優(yōu)先于繼承室谚。因為組合更加靈活毡鉴,它可以動態(tài)選擇類型崔泵。

class Actor{
    public void act(){};
}

class HappyActor extends Actor{
    public void act() {
        System.out.println("HappyActor");
    }
}


class SadActor extends Actor{
    public void act(){
        System.out.println("SadActor");
    }
}

class Stage{
    private Actor actor = new HappyActor();

    public void change(){
        actor = new SadActor();
    }

    public void performPlay(){
        actor.act();
    }
}

public class Transmogrify {
    public static void main(String[] args){
        Stage stage=new Stage();
        stage.performPlay();
        stage.change();
        stage.performPlay();
    }
}

在 Stage 中,performPlay() 的的輸出結(jié)果會隨著 change() 而改變猪瞬,

這樣一來憎瘸,我們在運行期間就獲得了動態(tài)靈活性,這被稱為是狀態(tài)模式陈瘦。

用繼承來表達行為間的差異幌甘,并用字段表達狀態(tài)上的變化。這是一條通用的編程準(zhǔn)則痊项,

這個例子中锅风,通過繼承得到了兩個不同的類,用于表達 act() 方法上的差異鞍泉,而 Stae

運用組合使自己的狀態(tài)發(fā)生變化皱埠。

向上轉(zhuǎn)型和向下轉(zhuǎn)型

向上轉(zhuǎn)型是安全的,因為子類一定具備了父類的接口塞弊。

但是漱逸,向下轉(zhuǎn)型不一定安全。因為子類可以擴展自己獨有的接口游沿。

向下轉(zhuǎn)型需要進行類型轉(zhuǎn)換饰抒,并且是在進入運行期對其進行類型檢查。

class Useful{
    public void f() {}
    public void g() {}
}

class MoreUseful extends Useful{
    public void f() {}
    public void g() {}
    public void u() {}
    public void v() {}
    public void w() {}
}


public class RTTI {
    public static void main(String[] args){
        Useful[] x = {
                new Useful(),
                new MoreUseful(),
        };
        x[0].f();
        x[1].g();
        ((MoreUseful) x[1]).w();
        ((MoreUseful) x[0]).w();
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诀黍,一起剝皮案震驚了整個濱河市袋坑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌眯勾,老刑警劉巖枣宫,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吃环,居然都是意外死亡也颤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門郁轻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翅娶,“玉大人,你說我怎么就攤上這事好唯〗吣” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵骑篙,是天一觀的道長蜕提。 經(jīng)常有香客問我,道長靶端,這世上最難降的妖魔是什么谎势? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任凛膏,我火速辦了婚禮,結(jié)果婚禮上它浅,老公的妹妹穿的比我還像新娘译柏。我一直安慰自己镣煮,他們只是感情好姐霍,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著典唇,像睡著了一般镊折。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上介衔,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天恨胚,我揣著相機與錄音,去河邊找鬼炎咖。 笑死赃泡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的乘盼。 我是一名探鬼主播升熊,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼绸栅!你這毒婦竟也來了级野?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤粹胯,失蹤者是張志新(化名)和其女友劉穎蓖柔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體风纠,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡况鸣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了竹观。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镐捧。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖栈幸,靈堂內(nèi)的尸體忽然破棺而出愤估,到底是詐尸還是另有隱情,我是刑警寧澤速址,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布玩焰,位于F島的核電站,受9級特大地震影響芍锚,放射性物質(zhì)發(fā)生泄漏昔园。R本人自食惡果不足惜蔓榄,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望默刚。 院中可真熱鬧甥郑,春花似錦、人聲如沸荤西。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽邪锌。三九已至勉躺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間觅丰,已是汗流浹背饵溅。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留妇萄,地道東北人蜕企。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像冠句,于是被迫代替她去往敵國和親轻掩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容