20、抽象類與模板設計模式

抽象類

基本概念

1、抽象類是含有抽象方法的類。抽象方法沒有方法體,必須用abstract定義。

abstract class A { // 抽象類
    public void fun(){方法體;} // 普通方法
    public abstract void print(); // 抽象方法
}

public class Demo {
    public static void main(String[] args) {
        A a = new A(); // 報錯,A是抽象類,無法實例化
    }
}

結果顯示,無法直接實例化抽象類對象.普通類的對象實例化後,該對象可以調用類中的屬性和方法.而抽象類中存在抽象方法,抽象方法沒有方法體無法調用,因此無法產生實例化對象.
2、抽象類使用原則:

(1)抽象類必須有子類;
(2)抽象類的子類(非抽象類時)必須覆寫抽象類中所有的抽象方法(強制子類進行方法覆寫)
(3)抽象類對象的實例化依靠子類完成,採用向上轉型方式。

範例:使用抽象類

abstract class A { // 抽象類
    public void fun() { // 普通方法
        System.out.println("普通方法");
    }

    public abstract void print(); // 抽象方法
}

class B extends A {
    // 強制要求對抽象方法進行覆寫,否則會報錯
    public void print() {
        System.out.println("覆寫後的抽象方法");
    }
}

public class Demo {
    public static void main(String[] args) {
        A a = new B(); // 向上轉型
        a.fun();
        a.print();
    }
}

由上述代碼,可知:

(1)抽象類的子類明確要求方法覆寫,而普通類沒有;
(2)抽象類只比普通類多了抽象方法,其他部分相同;
(3)抽象類對象必須經過向上轉型才能實例化;
(4)雖然子類可以繼承任何類,但開發中,普通類最好繼承抽象類。

使用限制

1、抽象類由於存在屬性,因此會有構造方法來初始化屬性。子類對象實例化時依然先執行父類構造方法,再調用子類構造方法。
2、抽象類不能使用final定義,因爲抽象類必須有子類。
3、抽象外部類不允許使用static定義,而抽象內部類可以使用static聲明。使用static定義的抽象內部類相當於抽象外部類,繼承時使用外部類.內部類的形式表示類名。

abstract class A { // 抽象類
    static abstract class B {
        public abstract void print();
    }
}

class X extends A.B {
    public void print() {
        System.out.println("*****");
    }
}

public class Demo {
    public static void main(String[] args) {
        A.B ab = new X(); // 向上轉型
        ab.print();
    }
}

4、static定義的方法可以沒有實例化對象的情況下直接調用,即使是抽象類中的static方法。

abstract class A { // 抽象類
    public static void print() {
        System.out.println("static方法");
    }
}

public class Demo {
    public static void main(String[] args) {
        A.print(); // static方法
        A a = new A() ; // 報錯
    }
}

5、有時抽象類只需要一個特定的子類操作,因此可以將該子類定義爲該抽象類的內部類。

abstract class A { // 抽象類
    public abstract void print();

    private static class B extends A { // 內部抽象類子類
        public void print() {
            System.out.println("Hello");
        }
    }

    public static A getInstance() { // 獲取B的實例化對象
        return new B();
    }
}

public class Demo {
    public static void main(String[] args) {
        // 客戶端得到抽象類對象時,B對其不可見
        A a = A.getInstance();
        a.print();
    }
}

上述設計在系統類庫中較爲常見,目的是:爲用戶隱藏不需要知道的子類。
6、觀察下述代碼:

abstract class A { // 抽象類
    // 1. 先調用父類構造
    public A() {
        this.print();
    }

    public abstract void print();
}

class B extends A {
    private int num = 100;
    // 3.調用子類構造,並初始化num = 30.運行結束,未輸出初始化後的num
    public B(int num) {
        this.num = num;
    }
    // 2. 父類構造調用子類的print,此時num = 0,打印輸出。
    public void print() {
        System.out.println("num = " + num);
    }
}

public class Demo {
    public static void main(String[] args) {
        new B(30); // 4. 結果爲0
    }
}

在構造方法執行完之前,屬性的內容均爲其對應的數據類型的默認值。子類在執行構造方法前必先執行父類的構造方法,因爲此時子類構造方法還沒執行,就調用print()輸出了num的值,所以num爲0.

模板設計模式

要求:設計三個類,通過類描述如下行爲:
(1)機器人:充電、工作;
(2)人:喫飯、工作、睡覺;
(3)豬:喫飯、睡覺
思路:定義一個抽象類,具有喫飯、睡覺、工作的抽象方法。根據子類的不同,具體實現抽象方法。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9Oy51FpX-1570848167779)(/18-2.png “思路圖”)]

abstract class Action {
    public static final int EAT = 1;
    public static final int SLEEP = 5;
    public static final int WORK = 7;

    public void command(int flag) {
        switch (flag) {
            case EAT:
                this.eat();
                break;
            case SLEEP:
                this.sleep();
                break;
            case WORK:
                this.work();
                break;
            case EAT + WORK:
                this.eat();
                this.work();
                break;
        }
    }
    // 不確定方法中的具體行爲,定義爲抽象類
    public abstract void eat();

    public abstract void sleep();

    public abstract void work();
}

定義子類

class Robot extends Action {
    public void eat() {
        System.out.println("機器人正在補充能量");
    }

    public void sleep() {
    }

    public void work() {
        System.out.println("機器人正在工作");
    }
}

class Human extends Action {
    public void eat() {
        System.out.println("人正在喫飯");
    }

    public void sleep() {
        System.out.println("人正在睡覺");
    }

    public void work() {
        System.out.println("人正在工作");
    }
}

class Pig extends Action {
    public void eat() {
        System.out.println("豬正在喫飯");
    }

    public void sleep() {
        System.out.println("豬正在睡覺");
    }

    public void work() {
    }
}

範例:測試程序

public class Demo {
    public static void main(String[] args) {
        fun(new Robot());
        fun(new Human());
        fun(new Pig());
    }

    public static void fun(Action act) {
        act.command(Action.EAT);
        act.command(Action.SLEEP);
        act.command(Action.WORK);
    }
}

結果顯示:子類要實現操作,必須按照Action類的標準。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章