目錄:html
1、接口的定義:java
首先讓咱們看一下接口的最新定義:What is an Interface,裏面提到:oracle
In the Java programming language, an interface is a reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods, and nested types. Method bodies exist only for default methods and static methods. Interfaces cannot be instantiated—they can only be implemented by classes or extended by other interfaces. 框架
再來看一下jdk1.7時的定義(具體原版定義官網已經找不到了,只能經過書籍及博客找到大概的版本):ide
An interface in Java is similar to a class, but the body of an interface can include only abstract methods and final fields (constants). A class implements an interface by providing code for each method declared by the interface.工具
咱們知道,在Java中,接口不是類,而是對類的一組需求描述,類遵循接口描述的統一格式進行定義。Java不支持多繼承,主要是爲了不多繼承會讓語言自己變得複雜(像C++),效率也會下降。而接口能夠提供多繼承的大多數好處,同時避免多重繼承的複雜性和低效性。spa
經過對比上面兩段定義,能夠看出最新的接口多了一些新的屬性,接下來主要圍繞這些新屬性來理解接口的定義。 設計
2、jdk7-jdk9,接口的變化:code
而後再來簡單看一下java interface的一個演變過程:htm
Constants (until Java 1.7)
Method signatures (until Java 1.7)
Nested types (until Java 1.7)
Default methods (since 1.8)
Static methods (since 1.8)
Private methods (since 1.9)
Private static methods (since 1.9)
3、default和public static method:
接着咱們先從一個8年前的問題開始:若是接口中有個方法的定義是能夠肯定的(實現該接口的類必須重複實現該方法),如何更優雅的設計這個接口?
文中提到了許多折中的方法:經過接口裏的靜態類、藉助工具類的靜態方法等。
但到了jdk8開始,這個問題被解決了:接口引入了default關鍵字和靜態方法(public static method),接口中經過default修飾的方法能夠有方法體,實現具體功能。看下面代碼:
public interface Skill{ void oldSkill(); default public void newSkill(){ System.out.print("實現了這個接口的類能夠不實現這個方法"); } public static newStaticSkiil(){ System.out.print("實現了這個接口的類能夠不實現這個靜態方法"); } }
引入default的目的官網有解釋:Default Method ,總的來講,引入default關鍵字是爲了當接口有新的行爲且現有依賴該接口的類與接口不需作任何改變,能夠再也不對於已實現該接口的類或繼承該接口的接口進行修改,能夠更加方便的拓展示有接口。
文中還指出,對於拓展了包含default method的接口或類:
abstract
.(從新聲明爲抽象方法)最後,還提到了jdk8開始,接口能夠支持靜態方法(public static method),這些都是爲了接口能夠有更好的演變性。
例如,jdk8開始引入的Lambda語法以及Stream API,都是在接口層實現的,所以default及public static method的提出算是爲新的設計服務,也響應了這麼久以來定義接口方法的呼聲。
Collection接口中,default關鍵字的身影:
引入default關鍵字後,有些地方可能要注意一下。首先是若是類實現的多個接口都包含了對同一個方法的default定義,那這個方法必須重寫,看下面例子:
public interface Ina { default void say(){ System.out.println("say a"); } }
public interface Inb { default void say(){ System.out.println("say b"); } }
若是classc在實現這兩個接口時不重寫say方法,那編譯器沒法肯定到classc調用say方法時,選擇哪個接口的方法。所以Classc必須重寫say:
public class classc implements Ina,Inb { @Override public void say(){ System.out.println("say c"); } }
固然,根據上面提示的3條規則,咱們也能夠把say方法從新聲明爲抽象方法:
public interface Ind extends Ina{ public abstract void say(); }
4、jdk9的補充:
jdk9中,接口引入的私有方法(private method)和私有靜態方法(private static method)。因爲不可被繼承,所以私有方法必須定義方法體纔有意義。同時也意味着接口的私有方法和私有靜態方法不可被實現該接口的類或繼承該接口的接口調用或重寫。私有方法(private method)和私有靜態方法(private static method)的提出都是對jdk8提出的default和public static method的補充。
默認方法和靜態方法能夠共享接口中的私有方法,所以避免了代碼冗餘,這也使代碼更加清晰。若是私有方法是靜態的,那這個方法就屬於這個接口的。而且沒有靜態的私有方法只能被在接口中的實例調用。
5、接口和抽象類的區別:
抽象類定義:An abstract class is a class that is declared abstract—it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed.
jdk8以後,接口的行爲再也不侷限在「描述」,接口的行爲具備了「定義」,對後期接口的演變和拓展提供了便利性,也表示類的行爲能夠多繼承了;固然即便是多了這些新特性,接口仍是和抽象類有一條最明顯的分界線:接口無狀態,抽象類只能單繼承。接口的成員域依然只能是常量,接口依然不能實例化。除此以外,還有權限上的區別,不支持protect聲明及包可見等屬性。
6、單繼承仍是多繼承:
不過,接口的這些新屬性是爲了更好的服務「單繼承多實現」的理念仍是更好的往「多繼承」靠攏呢?網上有不少不一樣的聲音,而本人更傾向於更好的服務「單繼承多實現」,咱們知道,最大的改變仍是jdk8提出的default和public static method,接口跳出了只能「聲明」方法,只有public abstract method的界限,從而使得原有框架上多出了更多優雅的設計。打破的規則若是可讓Java更優雅,那這規則就是應該被打破的。
參考:
《Java核心技術 卷1》
https://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html
https://en.wikipedia.org/wiki/Interface_(Java)