首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 介面與抽象類別深度解析

     編輯:Java 相關知識

Java 介面與抽象類別深度解析。本站提醒廣大學習愛好者:此文章僅供參考,不一定能完全符合您的需求。以下是完整分析正文


本文範例說明 Java 的介面與抽象類別。分享給大家供參考。詳細分析如下:

對於物件導向程式設計來說,抽象是其主要特點之一。在 Java 中,可以透過兩種形式來體現 OOP 的抽象:介面和抽象類別。這兩者有許多相似之處,也有許多不同之處。許多初學者會認為它們可以隨意互換使用,但實際上並非如此。今天我們就一起來學習一下 Java 中的介面和抽象類別。

如有不正確之處,請多包涵並歡迎批評指正,不勝感激。

一、抽象類別

在理解抽象類別之前,先來了解一下抽象方法。抽象方法是一種特殊的方法:它只有宣告,而沒有具體的實作。抽象方法的宣告格式為:

abstract void fun();

抽象方法必須用 abstract 關鍵字修飾。如果一個類別包含抽象方法,則稱為抽象類別,抽象類別必須在類別前用 abstract 關鍵字修飾。因為抽象類別中包含沒有具體實作的方法,所以無法用抽象類別建立物件。

這裡要注意一個問題:在《Java 程式設計思維》一書中,將抽象類別定義為「包含抽象方法的類別」,但發現如果一個類別不包含抽象方法,只是用 abstract 修飾的話也是抽象類別。也就是說抽象類別不一定必須包含抽象方法。個人認為這屬於鑽牛角尖的問題,因為如果一個抽象類別不包含任何抽象方法,為什麼還要設計為抽象類別?所以暫且記住這個概念,不用深究。

[public] abstract class ClassName {
    abstract void fun();
}

從這裡可以看出,抽象類別就是為了繼承而存在的。如果你定義了一個抽象類別,卻不去繼承它,那就等於白白建立了這個抽象類別,因為你無法用它來做任何事情。對於一個父類別,如果它的某個方法在父類別中實作出來沒有任何意義,必須根據子類別的實際需求來進行不同的實作,那麼就可以將這個方法宣告為 abstract 方法,此時這個類別也就變成 abstract 類別了。

包含抽象方法的類別稱為抽象類別,但並不意味著抽象類別中只能有抽象方法,它和普通類別一樣,同樣可以擁有成員變數和普通的成員方法。注意,抽象類別和普通類別的主要有三點不同:

  1. 抽象方法必須為 public 或 protected(因為如果為 private,則無法被子類別繼承,子類別就無法實作該方法),預設情況下默認為 public。
  2. 抽象類別無法用來建立物件;
  3. 如果一個類別繼承於一個抽象類別,則子類別必須實作父類別的抽象方法。如果子類別沒有實作父類別的抽象方法,則必須將子類別也定義為 abstract 類別。

在其他方面,抽象類別和普通的類別並沒有區別。

二、介面

介面,英文稱為 interface,在軟體工程中,介面泛指供他人呼叫的方法或函數。從這裡,我們可以理解到 Java 語言設計者的初衷,它是對行為的抽象。在 Java 中,定義一個介面的形式如下:

[public] interface InterfaceName { }

介面中可以包含變數和方法。但要注意,介面中的變數會被隱式地指定為 public static final 變數(而且只能是 public static final 變數,用 private 修飾會報編譯錯誤),而方法會被隱式地指定為 public abstract 方法且只能是 public abstract 方法(用其他關鍵字,如 private、protected、static、final 等修飾會報編譯錯誤),而且介面中所有的方法不能有具體的實作,也就是說,介面中的方法必須都是抽象方法。從這裡可以模糊看出介面和抽象類別的區別,介面是一種極端抽象的類型,它比抽象類別更「抽象」,而且一般情況下不在介面中定義變數。

要讓一個類別遵守某組特定的介面須要使用 implements 關鍵字,具體形式如下:

class ClassName implements Interface1, Interface2, [...] { }

可以看出,允許一個類別實作多個特定的介面。如果一個非抽象類別實作了某個介面,就必須實作該介面中的所有方法。對於實作某個介面的抽象類別,可以不實作該介面中的抽象方法。

三、抽象類別和介面的區別

1. 語法層面上的區別

  1. 抽象類別可以提供成員方法的實作細節,而介面中只能存在 public abstract 方法;
  2. 抽象類別中的成員變數可以是各種類型的,而介面中的成員變數只能是 public static final 類型的;
  3. 介面中不能包含靜態程式碼塊和靜態方法,而抽象類別可以有靜態程式碼塊和靜態方法;
  4. 一個類別只能繼承一個抽象類別,而一個類別卻可以實作多個介面。

2. 設計層面上的區別

  1. 抽象類別是對一種事物的抽象,即對類抽象,而介面是對行為的抽象。抽象類別是對整個類別整體進行抽象,包含屬性、行為,但介面卻是對類別局部(行為)進行抽象。舉個簡單的例子,飛機和鳥是不同類的事物,但它們都有一個共性,就是都會飛。那麼在設計時,可以將飛機設計為一個類別 Airplane,將鳥設計為一個類別 Bird,但不能將「飛行」這個特徵也設計為類別,因為它只是一個行為特徵,並不是對一類事物的抽象描述。此時可以將「飛行」設計為一個介面 Fly,包含方法 fly(),然後 Airplane 和 Bird 分別根據自己的需要實作 Fly 這個介面。至於有不同種類的飛機,如戰鬥機、民用飛機等直接繼承 Airplane 即可,對於鳥也同理,不同種類的鳥直接繼承 Bird 類別即可。從這裡可以看出,繼承是一個「是否是」的關係,而介面實作則是「有無」的關係。如果一個類別繼承了某個抽象類別,則子類別一定是抽象類別的種類,而介面實作則是有無、具有不具有的關係,例如鳥能否能飛(或是否具有飛行這個特徵),能飛行則可以實作這個介面,不能飛行就不實作這個介面。
  2. 設計層面不同,抽象類別作為許多子類別的父類別,它是一種模板式設計。而介面是一種行為規範,它是一種輻射式設計。什麼是模板式設計?最簡單例子,大家都用過 PPT 裡的模板,如果用模板 A 設計了 PPT B 和 PPT C,PPT B 和 PPT C 共同的部分就是模板 A 了,如果它們的共同部分需要修改,則只需要修改模板 A 就可以了,不需要重新對 PPT B 和 PPT C 進行修改。而輻射式設計,例如某個電梯都裝了某種報警器,一旦要更新報警器,就必須全部更新。也就是說對於抽象類別,如果需要添加新的方法,可以直接在抽象類別中添加具體實作,子類別可以不進行變更;而對於介面則不可,如果介面進行了變更,則所有實作這個介面的類別都必須進行相應的修改。

再看一個網上流傳最廣泛的例子:門和警報的例子:門都有 open() 和 close() 兩個動作,此時我們可以通過抽象類別和介面來定義這個抽象概念:

abstract class Door {
    public abstract void open();
    public abstract void close();
}

或是:

interface Door {
    public abstract void open();
    public abstract void close();
}

但現在如果我們需要門具有報警 alarm() 的功能,該如何實作?提供兩種思路:

  1. 將這三個功能都放在抽象類別裡面,但這樣一來所有繼承於這個抽象類別的子類別都擁有了報警功能,但有的門並不一定具有報警功能;
  2. 將這三個功能都放在介面裡面,需要用到報警功能的類別就需要實作這個介面中的 open() 和 close(),或者這個類別根本就不具備 open() 和 close() 這兩個功能,例如火災報警器。

從這裡可以看出,Door 的 open()、close() 和 alarm() 基本就屬於兩個不同領域內的行為,open() 和 close() 屬於門自身固有的行為特徵,而 alarm() 屬於延伸的附加行為。因此最好的解決方式是單獨將報警設計為一個介面,包含 alarm() 行為,Door 設計為單獨的一個抽象類別,包含 open 和 close 兩種行為。再設計一個報警門繼承 Door 類別並實作 Alarm 介面。

interface Alarm {
    void alarm();
}
abstract class Door {
    void open();
    void close();
}
class AlarmDoor extends Door implements Alarm {
    void open() { //.... }
    void close() { //.... }
    void alarm() { //.... }
}

希望本文所述對大家的 Java 程式設計有所幫助。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved