類,強調數據類型(自定義)的概念,在一些狀況下,並不能反映對象以及對象操做的本質。有時咱們關注的並不是對象的類型,而是對象的能力。java
接口聲明一組功能,做爲協議(約定),可是自身不去實現功能方法。接口形式的交互涉及兩方對象:一方實現接口,另外一方使用接口,雙方並不直接依賴,而是針對接口編程。程序員
接口定義編程
接口定義即聲明方法,制定功能協議。框架
Java 使用 interface
關鍵字聲明接口,修飾符通常採用 public
。
接口內部聲明方法時,一般不須要加修飾符,默認視爲 public abstract
。ide
接口實現設計
類能夠實現接口,表示類的對象具備接口(協議)制定的功能。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 抽象類...。
抽象類和接口是配合而非替代關係。接口聲明能力,抽象類提供默認實現(所有或部分方法)。