1. 程式人生 > >Java基礎5——深入理解抽象類和介面

Java基礎5——深入理解抽象類和介面

抽象類和介面

抽象方法和抽象類

  抽象方法是一種特殊的方法:它只有宣告,而沒有具體的實現。抽象方法的宣告格式為:

abstract void f();

  《Java程式設計思想》一書中將抽象類定義為包含抽象方法的類,但準確來說,包含抽象方法的類一定是抽象類,但抽象類不 一定有抽象方法,只要用abstract修飾即可為抽象類。(不必糾結具體的概念)

[public] abstract class Instrument{
    abstract void f();
}

  抽象類是對類(一類事物)的抽象, 抽象類就是為了繼承而存在的。它和普通類一樣,同樣可以擁有成員變數和普通的成員方法

。注意,抽象類和普通類的主要有三點區別:

  • 抽象方法必須為public或 protected的,預設情況下預設為public,因為抽象方法需要被子類繼承和實現。

  • 抽象類不能用來建立物件

  • 如果一個類繼承於一個抽象類,則子類必須實現父類的抽象方法。如果子類沒有實現父類的抽象方法,則必須將子類也定義為為abstract類。

介面

  在Java中,定一個介面的形式如下:

[public] interface InterfaceName {
}

  介面是對行為的抽象,其可以含有屬性和方法。屬性被隱式指定為public static final的,即全域性常量。(並且只能是public static final變數,用private修飾會報編譯錯誤

)方法被隱式執行為public abstract(介面中所有的方法不能有具體的實現,也就是說,介面中的方法必須都是抽象方法),即抽象方法。
  從這裡可以隱約看出介面和抽象類的區別,介面是一種極度抽象的型別,它比抽象類更加“抽象”,並且一般情況下不在介面中定義變數。
  要讓一個類遵循某組特地的介面需要使用implements關鍵字,具體格式如下:

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

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

抽象類和介面的區別

語法層面上的區別

  • 成員變數:抽象類中的成員變數可以是各種型別的,而介面中的成員變數只 能是常量,即public static final修飾的。
  • 成員方法:抽象類中的成員方法可以是抽象的也可以是普通的(有具體實現 的),而介面中的成員方法只能是public static修飾的。
  • 靜態結構:抽象類中可以有靜態程式碼塊和靜態方法,而介面中不能有靜態代 碼塊和靜態方法。
  • 靜態結構:抽象類中可以有靜態程式碼塊和靜態方法,而介面中不能有靜態代 碼塊和靜態方法。
  • 構造方法:抽象類中可以有構造器,而介面中沒有,但兩者都不能進行例項化,但可以定義抽象類和介面型別的引用。
  • 繼承與實現:一個類只能繼承一個抽象類,而一個類卻可以實現多個介面。

設計層面上的區別

  • 抽象類是對類(一類事物)的抽象,而介面是對行為的抽象。再具體一點說,抽象類是對一類事物整體(包括屬性和行為)進行抽象,而介面是對類 的區域性(僅對行為)進行抽象。如飛機、鳥和飛行而言,應分別將其設計為 類、類和介面。
  • 抽象類作為很多子類的父類,是一種模板式設計,而介面作為一種行為規範,是一種輻射式設計。如果需要新增新的方法,抽象類作為模板,可以直接新增帶具體實現的方法而無需改變子類,而介面作為規範,規範改變(新增行為),遵守規範的子類都必須進行相應的改動

抽象類和介面的應用場景

問題:「你在專案中哪些地方使用過介面和抽象類?具體是怎麼使用的?」
分析:門都有開啟和關閉兩個行為,此時若需要門具備警報行為,應該如何實現呢?
  其實,門的開啟和關閉屬於門本身固有的行為,而警報功能屬於門非固有的行為 (附加行為)。最佳解決方案是,將門設計為一個抽象類,包括開啟和關閉兩種 行為,而將警報設計為一個介面,包括警報行為,進而設計一個警報門繼承抽象 類並實現警報介面即可。

參考部落格:新增連結描述
  門和警報的例子:門都有 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 Alram {
    void alarm();
}
 
abstract class Door {
    void open();
    void close();
}
 
class AlarmDoor extends Door implements Alarm {
    void oepn() {
      //....
    }
    void close() {
      //....
    }
    void alarm() {
      //....
    }
}

小的細節

class A {

}
interface M extends N,L{//正確的,不會報錯;介面可以繼承多個其他的介面

}
interface N{

}
interface L{

}
interface 介面 {
    public final int i = 1;//變數預設都為public final修飾
    final A a = null;//基本資料型別和引用都一樣
    //protected void a();//報錯
    //private //報錯
    public abstract void a();// 方法都是public abstract修飾的。

    //void b(){} 報錯,接口裡的方法不能有方法體,也不能有{},只能有();

    // final void b();
    // 注意,抽象方法不能加final。因為final方法不能被重寫。
    //但如果抽象方法不被重寫那就沒有意義了,因為他根本沒有程式碼體。

}
abstract class 抽象類 {
    public final int i = 1;//變數並沒有被pulic和final修飾,只是一般的成員變數
    public final A a = null;

    private void A(){}//抽象類可以有具體方法
    abstract void AA();//抽象方法沒有方法體

    //private abstract void B();//報錯,組合非法
    // 因為private修飾的方法無法被子類重寫,所以和final一樣,使抽象方法無法被實現。

}

//抽象類也可以被例項化,舉例說明
abstract class B{
    B() {
        System.out.println("b init");
    }
}

class C extends B{
    C(){
        super();
        System.out.println("c init");
    }
}

public class 介面對比抽象類 {
    @Test
    public void test() {
        C c = new C();
        //結果先例項化B,再例項化C。
        //因為會呼叫到父類的構造方法。
    }
}
--------------------- 
作者:How 2 Play Life 
來源:CSDN 
原文:https://blog.csdn.net/a724888/article/details/80061047 
版權宣告:本文為博主原創文章,轉載請附上博文連結!