Java 接口與抽象類方式實現類的擴展

接口

類,強調數據類型(自定義)的概念,在一些狀況下,並不能反映對象以及對象操做的本質。有時咱們關注的並不是對象的類型,而是對象的能力java

接口聲明一組功能,做爲協議(約定),可是自身不去實現功能方法。接口形式的交互涉及兩方對象:一方實現接口,另外一方使用接口,雙方並不直接依賴,而是針對接口編程。程序員

接口定義編程

接口定義即聲明方法,制定功能協議。框架

Java 使用 interface 關鍵字聲明接口,修飾符通常採用 public
接口內部聲明方法時,一般不須要加修飾符,默認視爲 public abstractide

接口實現設計

類能夠實現接口,表示類的對象具備接口(協議)制定的功能。code

Java 使用 implements 關鍵字實現接口。
實現接口必須實現接口中聲明的全部方法。對象

public interface Printable {
    void print();
}

public class A6 implements Printable {
    public void print() {
        System.out.println("Hello");
    }

    public static void main(String args[]) {
        A6 obj = new A6();
        obj.print();
    }
}

接口擴展繼承

接口能夠擴展另外一個接口甚至多個接口,其方式與類能夠擴展(繼承)另外一個類的方式相同,使用 extends 關鍵字,可是類的繼承限制爲單繼承。接口

public interface BallGame extends Sport, Match {}

類的繼承與接口實現能夠共存,而且類能夠實現多個接口,從某種形式上構成多繼承結構。

public class Football extends Ball implements Sport, Match {}

等價於:

public class Football extends Ball implements BallGame {}

接口使用

與類不一樣,沒法直接 new 建立接口對象,可是能夠聲明接口類型的變量,引用實現了接口的類對象。

public interface Printable {
    void print();
}

public class Main {
    public static void main(String args[]) {
        Printable obj = new Printable() {
            @Override
            public void print() {
                System.out.println("Hello");
            }
        }
        obj.print();
    }
}

上述代碼看似建立接口對象,實則建立匿名內部類對象,由其實現接口。

接口有時更能反映出對象的本質(能力,一組功能協議)。所謂針對接口編程,使用接口而非具體實現接口的類型,統一處理不一樣類型對象,旨在下降耦合性,提升靈活性。固然,接口自己因爲沒有代碼實現,並無太大用處,須要依賴具體實現,才能生效。

抽象類

抽象類,顧名思義抽象的類,通常表明多個具體類(子類)上層公共的父類,做爲基類統一調用接口(方法)。

抽象類的意義

抽象方法和抽象類密不可分,抽象方法是未來做爲統一接口調用,而目前不知道如何實現的方法,只有經過子類重寫方法才能具體實現功能。

抽象類 Animal 定義 sound() 方法做爲統一接口調用,由於沒法肯定 sound() 方法該如何具體實現,Java 使用 abstract 關鍵字聲明方法爲抽象方法,無需定義方法體。子類 Dog 繼承抽象類 Animal,並具體實現 sound() 方法。

//abstract parent class
abstract class Animal {
    //abstract method
    public abstract void sound();
}

//Dog class extends Animal class
public class Dog extends Animal {

    public void sound() {
        System.out.println("Woof");
    }

    public static void main(String args[]) {
        Animal obj = new Dog();
        obj.sound();
    }
}

抽象類的使用

區別於具體類,抽象類沒法直接 new 建立抽象類對象,可是能夠聲明抽象類的變量,引用抽象類對應具體子類對象。

  • 定義了抽象方法的類必須聲明爲抽象類,可是抽象類能夠沒有抽象方法。
  • 抽象類和具體類同樣,能夠定義並實現具體方法,實例變量等。
  • 一個類在繼承抽象類後,必須實現抽象類的全部抽象方法,除非類本身也聲明爲抽象類。

抽象類介於接口和類之間。

接口與抽象類的區別及應用場景

相同點

  • 沒法建立對象(實例化)
  • 抽象方法由具體類實現(統一接口)
  • 做爲引用變量指向具體類對象(多態性)

不一樣點

對比條件 接口 抽象類
構造器 不存在 能夠有
具體方法 不存在 能夠有
實例變量 不存在 能夠有
「多繼承」 支持 不支持
接口 = 純抽象類(全部方法都是抽象方法)

應用場景

考慮多態性、統一接口調用的同時,須要實例變量、帶有默認實現的具體方法,使用抽象類。
聲明一組方法,卻又不想每一個具體類都實現全部方法,可使用抽象類,藉助空方法,交由具體類自行決定重寫其感興趣的方法。
具體類已經有父類,受 Java 限制只容許單繼承,只能選擇經過實現接口方式擴展類。

接口優於抽象類

《Effective Java》中討論到一條規則:「接口優於抽象類」。基於以下論斷:

  • 現有的類能夠很容易被更新,以實現新的接口。
    通常來講,沒法更新現有的類來擴展新的抽象類。若是但願讓兩個類擴展同一個抽象類,就必須把抽象類放到類型層次的高處,這樣會間接地傷害到類層次,迫使這個公共祖先的全部子類都擴展這個新的抽象類。
  • 接口是定義 mixin(混合類型)的理想選擇。
    混合類型除了自身類型以外,還能夠提供某些可選擇的行爲。例如,實現 Comparable 接口的實例之間能夠相互比較。
  • 接口容許咱們構造非層次結構的類型框架。
    類型層次對於組織某些事物是很是合適的,可是並不是全部事物都能被整齊地組織成一個嚴格的層次結構。類層次過於臃腫缺少靈活性,經過接口擴展行爲,必定程度上模擬多重繼承。

P.S. Java 限制只容許單繼承,即類不可能有一個以上的父類。

規則存在例外,即當演變的容易性比靈活性和功能更爲重要的時候,應該使用抽象類來定義類型。抽象類的演變比接口的演變要容易得多,當在抽象類中增長新的具體方法,它包含合理的默認實現,該抽象類的全部現有實現都將提供這個新的方法。接口一旦被公開發行,而且已被普遍實現,再想改變這個接口幾乎是不可能的。當在公有接口中增長方法,不可避免破壞實現這個接口的全部現有的類。

書中建議程序員爲「每一個重要接口都提供一個抽象的骨架實現(skeletal implementation)類,把接口和抽象類的優勢結合起來。接口的做用仍然是定義類型,可是骨架實現類接管了全部與接口實現相關的工做。」

Java 類庫中存在許多一個接口對應一個抽象類的設計,例如:Collection 接口與 AbstractCollection 抽象類、List 接口與AbstractList 抽象類...。

抽象類和接口是配合而非替代關係。接口聲明能力,抽象類提供默認實現(所有或部分方法)。

相關文章
相關標籤/搜索