《 Java 編程思想》CH08 多態

  • 在面向對象的程序設計語言中,多態是繼數據抽象和繼承以後的第三種基本特徵。
  • 多態經過分離作什麼和怎麼作,從另外一個角度將接口和實現分離開來。
  • 「封裝」經過合併特徵和行爲來建立新的數據類型。「實現隱藏」則經過將細節「私有化」把接口和實現分離開來,而多態的做用則是消除類型之間的耦合關係。

再論向上轉型 & 起色

  • 對象既能夠做爲它本身自己的類型使用,也能夠做爲它的基類使用,而這種把某個對象的引用視爲其基類的引用的作法被稱爲「向上轉型」
  • 將一個方法調用同一個方法主體關聯起來被稱爲綁定
    • 若在程序執行前進行綁定(若是有的話,由編譯器和連接器實現),叫作前期綁定
    • 若在運行時根據對象的類型進行綁定,則叫作後期綁定,也叫作動態綁定運行時綁定
  • Java 中除了 static 方法和 final 方法(private 方法屬於 final 方法)外,其餘全部方法都是後期綁定的。
  • Java 用動態綁定實現了多態後,咱們能夠只編寫與基類相關的代碼,而這些代碼能夠對全部該基類的導出類正確運行。
  • 多態的例子能夠參考練習2。
  • 在一個設計良好的 OOP 程序中,大多數或全部方法都只與基類接口通訊。這樣的程序是可擴展的,由於能夠從通用的基類繼承出新的數據類型,從而新添加一些功能。
  • 域沒有多態。
  • 若是一個方法是靜態的,那麼它的行爲就不具備多態性。靜態方法是與類,而不是與單個對象相關聯的。
  • 因爲 final 方法是沒法覆蓋的,因此 private 也是沒法覆蓋的,所以沒辦法進行動態綁定。即只有非 private 方法能夠覆蓋,可是「覆蓋」private 方法編譯器不會報錯,但運行結果每每與預期不符:
package com.company.ch08;

public class PrivateOverride {
    private void func() {
        System.out.println("private func()");
    }

    public static void main(String[] args) {
        PrivateOverride privateOverride = new Derived();
        privateOverride.func();
    }
}

class Derived extends PrivateOverride {
    public void func() { // 這裏其實沒有覆蓋。
        System.out.println("Derived func()");
    }
}
// private func()

構造器和多態

構造器不具備多態性,它們其實是 static 方法,只不過該 static 是隱式聲明的。java

構造器的調用順序

  • 基類的構造器老是在導出類的構造過程當中調用,並且按照繼承層次逐漸向上連接,以使每一個基類的構造器都能獲得調用。
  • 在導出類的構造器主體中,若是沒有明確指定調用某個基類構造器,它會默默地調用默認構造器。若是不存在默認構造器,編譯器就會出錯(若是某個類沒有任何構造器,則編譯器會給他添加一個默認構造器)

構造器的調用順序:安全

  1. 調用基類構造器。
  2. 按照聲明順序調用成員的初始化方法。
  3. 調用導出類的構造器的主體。

繼承與清理

Java 中一般不須要考慮清理的問題,垃圾回收機制會解決大部分問題,可是若是真的須要進行清理操做時,咱們須要手動調用某個特定的函數進行清理操做。由於繼承的緣由,咱們在覆蓋基類的清理函數時,須要調用基類版本的清理函數。一般在導出類清理函數的末尾。同時若是成員對象也有須要清理的話,也須要在清理函數中調用該成員的清理函數。調用的原則就是:清理的順序應該與初始化的順序相同app

若是某些成員對象存在於其餘一個或多個對象共享的狀況下,咱們不能簡單的調用其清理函數,咱們可使用「引用計數」來跟蹤訪問着共享對象的對象數量(就是C++中的shared_ptr)。dom

構造器內部的多態方法的行爲:

若是在一個構造器的內部調用正在構造的對象的某個動態綁定方法,會發生什麼?ide

package com.company.ch08;

class Glyph {
    void draw() {
        System.out.println("Glyph.draw()");
    }
    Glyph() {
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glyph() after draw()");
    }
}

class RoundGlyph extends Glyph {
    private int radius = 1;
    RoundGlyph(int r) {
        radius = r;
        System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
    }

    @Override
    void draw() {
        System.out.println("RoundGlyph.draw(), radius = " + radius);
    }
}

public class PolyConstructors {
    public static void main(String[] args) {
        new RoundGlyph(5);
    }
}
// Glyph() before draw()
// RoundGlyph.draw(), radius = 0
// Glyph() after draw()
// RoundGlyph.RoundGlyph(), radius = 5

從上面的輸出能夠看出,在基類中調用動態方法,的確會調用到對應導出類的方法,可是導出類的域卻未完成初始化。函數

初始化實例的過程:this

  1. 在其餘任何事物發生以前,將分配給對象的存儲空間初始化成二進制的零
  2. 調用基類構造器
  3. 按聲明順序調用成員的初始化方法
  4. 調用導出類的構造器主題。

在構造器內惟一可以安全調用的那些方法是基類中 final 方法(private 方法屬於 final 方法)設計

協變返回類型

Java SE5 中添加了協變返回類型,它表示在導出類中的被覆蓋方法能夠返回基類方法的返回類型的某種導出類型。code

package com.company.ch08;

class Grain {
    @Override
    public String toString() {
        return "Grain";
    }
}

class Wheat extends Grain {
    @Override
    public String toString() {
        return "Wheat";
    }
}

class Mill {
    Grain process() {
        return new Grain();
    }
}

class WheatMill extends Mill {
    @Override
    Wheat process() { // 關鍵在這裏,本來返回類型應該是 Grain,而這裏使用了 Grain 的導出類 Wheat
        return new Wheat();
    }
}

public class CovariantReturn {
    public static void main(String[] args) {
        Mill mill = new Mill();
        Grain grain = mill.process();
        System.out.println("grain = " + grain);
        mill = new WheatMill();
        grain = mill.process();
        System.out.println("grain = " + grain);
    }
}
// grain = Grain
// grain = Wheat

用繼承進行設計

咱們應該首先選擇「組合」,尤爲是不能十分肯定應該使用哪一種方法時。組合不會強制咱們的程序誰叫進入繼承的層次結構。並且,組合更加靈活,他能夠動態選擇類型。orm

package com.company.ch08;

class Actor {
    public void act() {}
}

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

class SadActor extends Actor {
    @Override
    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();
    }
}
// HappyActor
// SadActor

咱們經過在運行時將引用與不一樣的對象從新綁定起來,可讓咱們在運行期間得到動態靈活性(也稱爲「狀態模式」)。

繼承表示行爲間的差別,字段表示狀態上的變化

純繼承與擴展

  • is-a 關係(純繼承):只覆蓋在基類中已有的方法,不對其進行擴展
    • 導出類和基類有徹底相同的接口。
    • 只須要從導出類向上轉型,永遠不須要知道正在處理的對象的確切類型
  • is-like-a 關係:對基類進行了擴展
    • 導出類接口中擴展部分不能被基類訪問。

向下轉型與運行時類型識別

在 Java 中,全部轉型都會獲得檢查。即便咱們只是進行一次普通的加括弧形式的類型轉換,在進入運行期時仍然會對其進行檢查,若是不是咱們想要轉換的類型,那麼會返回一個 ClassCastException。

練習

練習1

package com.company.ch08;

public class Cycle {
    void run() {
        System.out.println("Cycle run");
    }
}

class Unicycle extends Cycle {
    @Override
    void run() {
        System.out.println("Unicycle run");
    }
}

class Bicycle extends Cycle {
    @Override
    void run() {
        System.out.println("Bicycle run");
    }
}

class Tricycle extends Cycle {
    @Override
    void run() {
        System.out.println("Tricycle run");
    }
}

class Test {
    static void ride(Cycle c) {
        c.run();
    }
    public static void main(String[] args) {
        Unicycle unicycle = new Unicycle();
        Bicycle bicycle = new Bicycle();
        Tricycle tricycle = new Tricycle();

        unicycle.run();
        bicycle.run();
        tricycle.run();
    }
}
// Unicycle run
// Bicycle run
// Tricycle run

練習2

package com.company.ch08;

public class Shape {
    public void draw() {}
    public void erase() {}
}
package com.company.ch08;

public class Circle extends Shape{
    @Override
    public void draw() {
        System.out.println("Circle draw");
    }

    @Override
    public void erase() {
        System.out.println("Circle erase");
    }
}
package com.company.ch08;

public class Square extends Shape{
    @Override
    public void draw() {
        System.out.println("Square draw");
    }

    @Override
    public void erase() {
        System.out.println("Square erase");
    }
}
package com.company.ch08;

public class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("Triangle draw");
    }

    @Override
    public void erase() {
        System.out.println("Triangle erase");
    }
}
package com.company.ch08;

import java.util.Random;

// 工廠模式
public class RandomShapeGenerator {
    private Random random = new Random(47);
    public Shape next() {
        switch (random.nextInt(3)) {
            default:
            case 0: return new Circle();
            case 1: return new Square();
            case 2: return new Triangle();
        }
    }
}
package com.company.ch08;

public class Shapes {
    private static RandomShapeGenerator randomShapeGenerator = new RandomShapeGenerator();

    public static void main(String[] args) {
        Shape[] shapes = new Shape[9];
        for (int i = 0;i < 9;i++) {
            shapes[i] = randomShapeGenerator.next();
        }
        for (Shape shape: shapes) {
            shape.draw();
        }
    }
}
// Triangle draw
// Triangle draw
// Square draw
// Triangle draw
// Square draw
// Triangle draw
// Square draw
// Triangle draw
// Circle draw

練習3

public class Shape {
    public void draw() {}
    public void erase() {}
    public void info() {
        System.out.println("Shape info");
    }
}

即便導出類沒有覆蓋它,可是因爲繼承的緣由,導出類任然會有該方法。

package com.company.ch08;

public class Circle extends Shape{
    @Override
    public void draw() {
        System.out.println("Circle draw");
    }

    @Override
    public void erase() {
        System.out.println("Circle erase");
    }

    @Override
    public void info() {
        System.out.println("Circle info");
    }
}
package com.company.ch08;

public class Shapes {
    private static RandomShapeGenerator randomShapeGenerator = new RandomShapeGenerator();

    public static void main(String[] args) {
        Shape[] shapes = new Shape[9];
        for (int i = 0;i < 9;i++) {
            shapes[i] = randomShapeGenerator.next();
        }
        for (Shape shape: shapes) {
            shape.info();
        }
    }
}
// Shape info
// Shape info
// Circle info
// Circle info
// Shape info
// Shape info
// Shape info
// Shape info
// Circle info

若是隻有一個導出類Circle覆蓋了該方法,只有在正式類型爲Circle的Shape調用info時,纔會調用到覆蓋後的方法,而其他的則是調用到基類的方法。

練習4

class Line extends Shape {
    @Override
    public void draw() {
        System.out.println("Line draw");
    }

    @Override
    public void erase() {
        System.out.println("Line erase");
    }
}

public class Shapes {
    private static RandomShapeGenerator randomShapeGenerator = new RandomShapeGenerator();

    public static void main(String[] args) {
        Shape[] shapes = new Shape[9];
        for (int i = 0;i < 9;i++) {
            shapes[i] = randomShapeGenerator.next();
        }
        for (Shape shape: shapes) {
            shape.draw();
        }
        shapes[0] = new Line();
        shapes[0].draw();
    }
}

//Shape info
//Shape info
//Circle info
//Circle info
//Shape info
//Shape info
//Shape info
//Shape info
//Circle info

練習5

package com.company.ch08;

public class Cycle {
    void run() {
        System.out.println("Cycle run");
    }
    int wheels() {
        return 0;
    }
}

class Unicycle extends Cycle {
    @Override
    void run() {
        System.out.println("Unicycle run");
    }

    @Override
    int wheels() {
        return 1;
    }
}

class Bicycle extends Cycle {
    @Override
    void run() {
        System.out.println("Bicycle run");
    }

    @Override
    int wheels() {
        return 2;
    }
}

class Tricycle extends Cycle {
    @Override
    void run() {
        System.out.println("Tricycle run");
    }

    @Override
    int wheels() {
        return 3;
    }
}

class Test {
    static void ride(Cycle c) {
        c.run();
    }
    public static void main(String[] args) {
        Unicycle unicycle = new Unicycle();
        Bicycle bicycle = new Bicycle();
        Tricycle tricycle = new Tricycle();

        unicycle.run();
        bicycle.run();
        tricycle.run();

        Cycle[] cycles = new Cycle[]{unicycle, bicycle, tricycle};
        for (Cycle cycle: cycles) {
            System.out.println("cycle.wheels() = " + cycle.wheels());
        }
    }
}
// Unicycle run
// Bicycle run
// Tricycle run
// cycle.wheels() = 1
// cycle.wheels() = 2
// cycle.wheels() = 3

練習6

package com.company.ch08;



enum Note {
    MIDDLE_C, C_SHARP, B_FLAT;
}

class Instrument {
    void play(Note n) {
        System.out.println("Instrument.play() n = " + n);
    }
    @Override
    public String toString() {
        return "Instrument";
    }
    void adjust() {
        System.out.println("Adusting Instrument");
    }
}

class Wind extends Instrument {
    @Override
    void play(Note n) {
        System.out.println("Wind.play() n = " + n);
    }
}

class Percussion extends Instrument {
    @Override
    void play(Note n) {
        System.out.println("Percussion.play() n = " + n);
    }

    @Override
    public String toString() {
        return "Percussion";
    }

    @Override
    void adjust() {
        System.out.println("Adjusting Percussion");
    }
}

class Stringed extends Instrument {
    @Override
    void play(Note n) {
        System.out.println("Stringed.play() n = " + n);
    }

    @Override
    public String toString() {
        return "Stringed";
    }

    @Override
    void adjust() {
        System.out.println("Adjusting Stringed");
    }

}

class Brass extends Wind {
    @Override
    void play(Note n) {
        System.out.println("Brass.play() n = " + n);
    }

    @Override
    void adjust() {
        System.out.println("Adjusting Brass");
    }
}

class Woodwind extends Wind {
    @Override
    void play(Note n) {
        System.out.println("Woodwind.play() n = " + n);
    }

    @Override
    public String toString() {
        return "Woodwind";
    }
}

public class Music3 {
    public static void tune(Instrument i) {
        i.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] instruments) {
        for (Instrument instrument: instruments) {
            tune(instrument);
        }
    }

    public static void main(String[] args) {
        Instrument[] instruments = {
                new Wind(),
                new Percussion(),
                new Stringed(),
                new Brass(),
                new Woodwind(),
        };
        tuneAll(instruments);
        for (Instrument instrument: instruments) {
            System.out.println(instrument);
        }
    }
}
// Wind.play() n = MIDDLE_C
// Percussion.play() n = MIDDLE_C
// Stringed.play() n = MIDDLE_C
// Brass.play() n = MIDDLE_C
// Woodwind.play() n = MIDDLE_C
// Instrument
// Percussion
// Stringed
// Instrument
// Woodwind

練習7

class Piano extends Instrument {
    @Override
    void play(Note n) {
        System.out.println("Piano.play() n = " + n);
    }

    @Override
    public String toString() {
        return "Piano";
    }

    @Override
    void adjust() {
        System.out.println("Adjusting Piano");
    }
}

public class Music3 {
    public static void tune(Instrument i) {
        i.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] instruments) {
        for (Instrument instrument: instruments) {
            tune(instrument);
        }
    }

    public static void main(String[] args) {
        Instrument[] instruments = {
                new Wind(),
                new Percussion(),
                new Stringed(),
                new Brass(),
                new Woodwind(),
                new Piano(),
        };
        tuneAll(instruments);
        for (Instrument instrument: instruments) {
            System.out.println(instrument);
        }
    }
}
// Wind.play() n = MIDDLE_C
// Percussion.play() n = MIDDLE_C
// Stringed.play() n = MIDDLE_C
// Brass.play() n = MIDDLE_C
// Woodwind.play() n = MIDDLE_C
// Piano.play() n = MIDDLE_C
// Instrument
// Percussion
// Stringed
// Instrument
// Woodwind
// Piano

練習8

class InstrumentGenerator {
    private Random random = new Random(42);
    public Instrument next() {
        switch (random.nextInt(6)) {
            default:
            case 0: return new Wind();
            case 1: return new Percussion();
            case 2: return new Stringed();
            case 3: return new Brass();
            case 4: return new Woodwind();
            case 5: return new Piano();
        }
    }
}

public class Music3 {
    public static void tune(Instrument i) {
        i.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] instruments) {
        for (Instrument instrument: instruments) {
            tune(instrument);
        }
    }



    public static void main(String[] args) {
        Instrument[] instruments = new Instrument[10];
        InstrumentGenerator instrumentGenerator = new InstrumentGenerator();
        for (int i = 0;i < 10; i++) {
            instruments[i] = instrumentGenerator.next();
        }
        tuneAll(instruments);
        for (Instrument instrument: instruments) {
            System.out.println(instrument);
        }
    }
}

// Stringed.play() n = MIDDLE_C
// Brass.play() n = MIDDLE_C
// Wind.play() n = MIDDLE_C
// Stringed.play() n = MIDDLE_C
// Wind.play() n = MIDDLE_C
// Percussion.play() n = MIDDLE_C
// Piano.play() n = MIDDLE_C
// Stringed.play() n = MIDDLE_C
// Percussion.play() n = MIDDLE_C
// Piano.play() n = MIDDLE_C
// Stringed
// Instrument
// Instrument
// Stringed
// Instrument
// Percussion
// Piano
// Stringed
// Percussion
// Piano

練習9

package com.company.ch08;

public class Rodent {
    void eat() {
        System.out.println("Rodent.eat()");
    }

    public static void main(String[] args) {
        Rodent[] rodents = new Rodent[] {
                new Rodent(),
                new Mouse(),
                new Gerbil(),
                new Hamster(),
        };
        for (Rodent rodent: rodents) {
            rodent.eat();
        }
    }
}

class Mouse extends Rodent {
    @Override
    void eat() {
        System.out.println("Mouse.eat()");
    }
}

class Gerbil extends Rodent {
    @Override
    void eat() {
        System.out.println("Gerbil.eat()");
    }
}

class Hamster extends Rodent {
    @Override
    void eat() {
        System.out.println("Hamster.eat()");
    }
}
// Rodent.eat()
// Mouse.eat()
// Gerbil.eat()
// Hamster.eat()

練習10

package com.company.ch08;

class Base {
    void func1() {
        func2();
    }
    void func2() {
        System.out.println("Base");
    }
}

public class Ex10 extends Base {
    @Override
    void func2() {
        System.out.println("Ex10");
    }

    public static void main(String[] args) {
        Base base = new Ex10();
        base.func1();
    }
}
// Ex10

由於func2既不是static也不是final,因此他是動態綁定的,所以基類的 func1 中調用 func2 方法也是調用到導出類的 func2。

練習11

package com.company.ch08;

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()");
    }
}

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

public class Sandwich extends PortableLunch {
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Lettuce l = new Lettuce();
    private Pickle p = new Pickle();
    public Sandwich() {
        System.out.println("Sandwich()");
    }

    public static void main(String[] args) {
        new Sandwich();
    }
}

練習12

package com.company.ch08;

public class Rodent {
    Rodent() {
        System.out.println("Rodent");
    }
    void eat() {
        System.out.println("Rodent.eat()");
    }

    public static void main(String[] args) {
        Rodent[] rodents = new Rodent[] {
                new Rodent(),
                new Mouse(),
                new Gerbil(),
                new Hamster(),
        };
        for (Rodent rodent: rodents) {
            rodent.eat();
        }
    }
}

class Mouse extends Rodent {
    Mouse() {
        System.out.println("Mouse");
    }
    @Override
    void eat() {
        System.out.println("Mouse.eat()");
    }
}

class Gerbil extends Rodent {
    Gerbil() {
        System.out.println("Gerbil");
    }
    @Override
    void eat() {
        System.out.println("Gerbil.eat()");
    }
}

class Hamster extends Rodent {
    Hamster() {
        System.out.println("Hamster");
    }
    @Override
    void eat() {
        System.out.println("Hamster.eat()");
    }
}

練習13

package com.company.ch08;

class Shared {
    private int refcount = 0;
    private static long counter = 0;
    private final long id = counter++;
    public Shared() {
        System.out.println("Create " + this);
    }
    void addRef() {
        refcount++;
    }
    protected void dispose() {
        if(--refcount == 0)
            System.out.println("Disposing " + this);
    }

    @Override
    public String toString() {
        return "Shared{" +
                "id=" + id +
                '}';
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize()");
        if (refcount != 0) {
            System.out.println("refcount != 0");
        }
        super.finalize();
    }
}

class Composing {
    private Shared shared;
    private static long counter = 0;
    private final long id = counter++;
    public Composing(Shared shared) {
        System.out.println("Creating " + this);
        this.shared = shared;
        this.shared.addRef();
    }
    protected void dispose() {
        System.out.println("disposing " + this);
        shared.dispose();
    }

    @Override
    public String toString() {
        return "Composing{" +
                "id=" + id +
                '}';
    }
}

public class ReferenceCounting {
    public static void main(String[] args) {

//        Shared shared = new Shared();
//        Composing[] composings = {
//                new Composing(shared), new Composing(shared),
//                new Composing(shared), new Composing(shared),
//                new Composing(shared)
//        };
//
//        for (Composing composing: composings) {
//            composing.dispose();
//        }
        new Composing(new Shared());
        System.gc();
    }
}

練習14

練習15

package com.company.ch08;

class Glyph {
    void draw() {
        System.out.println("Glyph.draw()");
    }
    Glyph() {
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glyph() after draw()");
    }
}

class RoundGlyph extends Glyph {
    private int radius = 1;
    RoundGlyph(int r) {
        radius = r;
        System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
    }

    @Override
    void draw() {
        System.out.println("RoundGlyph.draw(), radius = " + radius);
    }
}

class RectangularGlygh extends Glyph {
    private int length;
    RectangularGlygh(int length) {
        this.length = length;
        System.out.println("RectanguarGlygh length = " + length);
    }

    @Override
    void draw() {
        System.out.println("RectanguarGlygh.draw() length = " + length);
    }
}

public class PolyConstructors {
    public static void main(String[] args) {
        new RectangularGlygh(10);
    }
}
// Glyph() before draw()
// RectanguarGlygh.draw() length = 0
// Glyph() after draw()
// RectanguarGlygh length = 10

練習16

package com.company.ch08;

class Status {
    void func() {}
}

class StatusA extends Status {
    void func() {
        System.out.println("Status A");
    }
}

class StatusB extends Status {
    void func() {
        System.out.println("Status B");
    }
}

class StatusC extends Status {
    void func() {
        System.out.println("Status C");
    }
}

class AlterStatus {
    Status status = new StatusA();
    void A() {
        status = new StatusA();
    }
    void B() {
        status = new StatusB();
    }
    void C() {
        status = new StatusC();
    }
    void call() {
        status.func();
    }
}

public class Starship {
    public static void main(String[] args) {
        AlterStatus alterStatus = new AlterStatus();
        alterStatus.call();
        alterStatus.B();
        alterStatus.call();
        alterStatus.C();
        alterStatus.call();
        alterStatus.A();
        alterStatus.call();
    }
}
// Status A
// Status B
// Status C
// Status A

練習17

package com.company.ch08;

public class Cycle {
    void run() {
        System.out.println("Cycle run");
    }
    int wheels() {
        return 0;
    }
}

class Unicycle extends Cycle {
    @Override
    void run() {
        System.out.println("Unicycle run");
    }

    @Override
    int wheels() {
        return 1;
    }
    
    void balance() {}
}

class Bicycle extends Cycle {
    @Override
    void run() {
        System.out.println("Bicycle run");
    }

    @Override
    int wheels() {
        return 2;
    }

    void balance() {}
}

class Tricycle extends Cycle {
    @Override
    void run() {
        System.out.println("Tricycle run");
    }

    @Override
    int wheels() {
        return 3;
    }
}

class Test {
    static void ride(Cycle c) {
        c.run();
    }
    public static void main(String[] args) {
        


        Cycle[] cycles = new Cycle[]{new Unicycle(), new Bicycle(), new Tricycle()};
//        for(Cycle cycle: cycles) {
//            cycle.balance(); // 沒法調用
//        }
        Unicycle unicycle = (Unicycle)cycles[0];
        Bicycle bicycle = (Bicycle)cycles[1];
        Tricycle tricycle = (Tricycle)cycles[2];
        
        unicycle.balance();
        bicycle.balance();
//        tricycle.balance(); //沒法調用
    }
}

本文首發於Code & Fun

相關文章
相關標籤/搜索