之前Java接口中的方法默認都是public abstract,成員變量默認都是public static final,偶然發現接口中可以有default類型的方法,才知道java8中接口可以有自己的實現了。那么jdk1.8究竟對接口做了哪些修改呢?
(1) 增加default方法。default方法作用范圍也是public,只是有了具體實現的方法體。對已有的接口,如果想對接口增加一個新方法,那么需要對所有實現該接口的類進行修改。而有了default方法,可以解決該問題。
(2) 新增static方法。static修飾的方法也是非抽象方法,使用同類的靜態方法一樣,給方法的調用帶來了方便。程序入口main方法也是static,現在接口也可以運行了。
例如下面在InterfaceA中定義了一個default方法,一個static方法:
public interface InterfaceA { default String f(){ return"this is InterfaceA"; } static String getName(){ return "InterfaceA"; } }
那么在實現類中可以直接調用接口的default方法,通過接口名.方法名調用static方法
public class ImplClass implements InterfaceA { public static void main(String[] args) { System.out.println(new ImplClass().f()); System.out.println(InterfaceA.getName()); } }
結果:
但是注意,如果一個類同時實現了兩個擁有相同方法簽名(相同的方法名、參數)、返回類型的default方法后,需要在類中重寫default方法,否則編譯器會因為不知道應該調用哪一個接口中的default方法而報錯
再定義一個InterfaceB接口,和InterfaceA接口擁有相同方法簽名、返回類型的f()
public interface InterfaceB { default String f(){ return "this is InterfaceB"; } }
ImplClass同時實現InterfaceA和InterfaceB,這時編譯器會報錯:
重寫接口中default方法后,編譯器會執行重寫后的方法:
public class ImplClass implements InterfaceA,InterfaceB { @Override public String f(){ return "this is ImplClass"; } public static void main(String[] args) { System.out.println(new ImplClass().f()); } }
結果:
如果一個類同時繼承的父類和實現的接口擁有相同簽名、返回類型時,當該類未重寫方法,直接調用時,將會調用父類中的方法:
再定義一個父類FatherC,擁有和InterfaceA同簽名、返回類型的方法f()
public class FatherC { public String f(){ return "this is FatherC"; } }
ImplClass實現InterfaceA的同時繼承FatherC,未重寫方法f(),直接調用時,將會調用父類中的方法:
public class ImplClass extends FatherC implements InterfaceA { public static void main(String[] args) { System.out.println(new ImplClass().f()); } }
結果:
接口已經越來越向類靠近了,所以現在接口和抽象類的區別有:
1. 雖然接口和抽象類都不能被實例化,但是抽象類可以有構造器,接口沒有構造器
2. 抽象類單繼承(只能繼承一個類),接口多繼承(能繼承多個接口)
3. 抽象類中方法可以有public、protected、默認(包)甚至private范圍的方法,接口只能有public范圍的方法(即使是default也是public范圍的)