抽象

介紹關鍵字 abstract 的用法及其物件導向意義。

何謂抽象? What is Abstract?

抽象可以想像成一種概念,並不存在於世界上。

在『多型』的章節中,我們有一個Animal的類別,但現實生活中有這個東西嗎? 動物只是一個概念,並沒有一種生物叫作動物。 狗、鳥、魚都是實際存在於世界上的實體,他們都是動物,現實中卻沒有一個實體叫作動物。

如果聽起來卡卡的,再反覆讀幾次。 所以我們可以把動物視為一種『概念』,他是抽象的,不存在於世界上的。 而Dog、Bird、Fish都具備這個概念的特質,所以繼承Animal。

關鍵字 abstract

abstract 是一個Java的關鍵字,是一個修飾子,可以用來修飾的有: 1. 類別 2. 方法

抽象類別 abstract class

利用abstract來修飾類別,可以使類別變成抽象類別,使用方法:

abstract class 類別名稱{
    // 成員定義...
}

在類別定義前加上修飾子abstract,就可以定義抽象類別。

上面我們提到,抽象是一個概念,而不是一個存在的實體。同樣的,抽象類別不能被實體化

範例程式,抽象類別定義:

abstract class Animal{
    int height,weight;
    void move(){
        System.out.println("move...move...");
    }
}

範例程式,實體化測試:

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

        Animal ani = new Animal();

    }// end of main(String[])
}// end of class Test

執行結果:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Cannot instantiate the type Animal

發生編譯錯誤,因為抽象類別無法被實體化

阿我設計類別就是為了實體化產生物件阿,現在跟我說這個類別無法被實體化那我幹嘛要寫? 先別急,這個抽象類別無法被實體化,但是他可以『被繼承』。

class Dog extends Animal{

}

這樣Dog類別就有Animal類別定義好的東西,在加上他自己的成員,就可以用來創造Dog的物件。

因此可以說,抽象類別是用來被繼承的

擁有這個概念的類別,繼承抽象類別,在程式撰寫上就可以利用多型的概念上程式更有邏輯性。

以上一篇『多型』的程式例子來說,Animal這個抽象的概念不應該被實體化,因為現實中不從在一種東西叫作『動物』,而狗、鳥、魚都是實際存在的東西,都擁有『動物』這個概念的特性,所以比較好的寫法應該定義為:

abstract class Animal {
    // 成員定義
}

class Dog extends Animal {
    // 成員定義
}

class Bird extends Animal {
    // 成員定義
}

class Fish extends Animal {
    // 成員定義
}

這樣寫很清楚告訴說,動物是一種概念,不能被實體化。而Dog、Bird、Fish具有動物的特性,可以被實體化存在於世界上(記憶體中)。

抽象方法 abstract method

利用修飾子abstract,可以使方法變成抽象方法,抽象方法只能寫方法的原型,無法定義方法的本體。

方法的原型? 只定義修飾子、回傳值型態、方法名稱、參數型態,而沒有『大括號{}』的部分就是方法原型。

方法的本體就是用『大括號{}』定義的東西,有寫{}就算有定義,不管裡面有沒有程式敘述。

使用格式:

abstract <修飾子> 回傳型態 方法名稱(<參數...>);

範例:

abstract void eat();

錯誤範例:

abstract void eat(){    // 編譯錯誤:Abstract methods do not specify a body
    // 不管有沒有寫東西,都編譯錯誤,抽象方法不能定義方法本體
}

好,那現在問題又來了,我要這個沒有本體的抽象方法幹嘛? 只有原型的方法做不了任何事阿!

沒錯,所以必須要有其他人『覆寫』這個抽象方法。

程式範例,定義Animal為抽象類別,有一個抽象方法eat():

abstract class Animal {
    abstract void eat();
}
class Dog extends Animal{
    void eat(){
        System.out.println("啃骨頭...");
    }
}

在上述程式中,母類別Animal定義了一個抽象方法eat(),宣告這個eat()方法回傳值是void且不帶任何參數。 子類別必須覆寫這個方法,為這個方法定義本體,也就是『實作implement』這個方法。

特別注意的是,抽象方法只能定義在抽象類別中。 (否則會編譯錯誤)

abstract method can only be defined by an abstract class

有了抽象方法,那我們的抽象類別就可以定義的更簡潔了。

範例程式:

abstract class Animal{
    int weight,heigh;
    void setValue(int w,int h){
        this.weight = w;
        this.height = h;
    }
    abstract void eat();
}
class Dog extends Animal{
    void eat(){
        System.out.println("啃骨頭...");
    }
}
class Bird extends Animal{
    void eat(){
        System.out.println("早起吃蟲...");
    }
}

上述程式中,將Animal類別定義為抽象,裡面把eat()定義為抽象方法,任何繼承這個Animal的子類別都必須實作屬於他們自己的eat(),同時都擁有Animal所定義的成員。

這樣做的目的是因為繼承一個類別,子類別就可以當作母類別來使用,但一般母類別都定義的很一般化,所以透過abstract關鍵字『強制』子類別繼承這個母類別後必須實作屬於自己的方法,也讓物件導向的設計邏輯更符合一般的現實概念。

最後整理一下

關鍵字abstract,抽象,可以修飾:

  1. 類別

    讓類別變成抽象類別,不能建立實體,專門用來『被繼承』。

  2. 方法

    讓方法變成抽象方法,只能定義原型,專門用來『被覆寫』。

其中抽象方法只能被定義在抽象類別中。

Last updated