在JDK1.8以前,介面(interface)沒有提供任何具體的實現,在《JAVA編程思想》中是這樣描述的:“interface這個關鍵字產生了一個完全抽象的類,它根本就沒有提供任何具體的實現。它允許創建者確定方法名、參數列表和返回類型,但是沒有任何方法體。介面只提供了形式,而未提供任何具體實現”。 ...
在JDK1.8以前,介面(interface)沒有提供任何具體的實現,在《JAVA編程思想》中是這樣描述的:“interface這個關鍵字產生了一個完全抽象的類,它根本就沒有提供任何具體的實現。它允許創建者確定方法名、參數列表和返回類型,但是沒有任何方法體。介面只提供了形式,而未提供任何具體實現”。
但是這一限制在JDK1.8中被打破了,JDK1.8開始,介面允許定義預設方法和靜態方法。
介面預設方法的語法很簡單,即:
default關鍵字 methodName(參數列表) { // 實現體 }
介面靜態方法語法與類的靜態方法類似,不同的是介面靜態方法的修飾符只能是public。
1、預設方法
為了提高代碼的可重用性。介面的預設方法有助於在擴展系統功能的同時,不對現有的繼承關係及類庫產生很大的影響。例如在JDK1.8中,Java集合框架的Collection介面增加了stream()等預設方法,這些預設方法即增強了集合的功能,又能保證對低版本的JDK的相容。
舉個簡單的例子,假如有一個Animal介面其中有fly()和swim()方法,有一個鳥類Bird和一個魚類Fish同時實現這個介面,代碼如下:
Animal介面:
1 public interface Animal { 2 void run(); 3 void swim(); 4 }
Bird.java
public class Bird implements Animal { @Override public void swim() { // do nothing } @Override public void fly() { System.out.println("birds can fly..."); } }
Fish.java
1 public class Fish implements Animal { 2 3 @Override 4 public void swim() { 5 System.out.println("fish can swim......"); 6 } 7 8 @Override 9 public void fly() { 10 // donothing 11 } 12 }
從上代碼可以看到,因為Animal中定義了fly()和swim()方法,所以所有實現它的類都要覆寫這兩個方法,在Bird類中,鳥會飛,不會游泳,但是又必須要實現swim()方法,Fish類不會飛,但是又必須要實現fly()方法。代碼出現冗餘。
假如現在又有了新的需求,需要在Animal介面中再增加一個cry()方法,那麼之前所有實現了Animal介面的方法勢必都在再覆寫cry()方法,整個系統中可能會有很多地方需要同步修改,而此時,default方法和靜態方法就顯得尤為必要了。
改寫上面的例子:
Animal.java
1 public interface Animal { 2 default void fly() { 3 System.out.println("birds can fly..."); 4 } 5 6 default void swim() { 7 System.out.println("fishes can swim......"); 8 } 9 }
Bird.java
1 public class Bird implements Animal { 2 }
Fish.java
1 public class Fish implements Animal { 2 }
測試類:
1 public class TestMain { 2 3 public static void main(String[] args) { 4 5 Bird bird = new Bird(); 6 bird.fly(); 7 8 Fish fish = new Fishe(); 9 fish.swim(); 10 } 11 }
運行結果:
birds can fly...
fishes can swim......
從修改後代碼可以看出,代碼得到了復用,Animal實現類中也沒有了冗餘。
2、靜態方法
假如有一個Animal工廠介面,該介面中有一個靜態方法create()專門生產不同的Animal,在JDK1.8後由於引入了Lambda表達式,使子類不用覆寫該介面的create()方法也可以生產任意的Animal,代碼如下:
1 public interface AnimalFactory { 2 3 static Animal create(Supplier<Animal> supplier) { 4 return supplier.get(); 5 } 6 }
測試類:
1 public class TestAnimalFactory { 2 3 public static void main(String[] args) { 4 5 // 生產一隻鳥 6 Animal bird = AnimalFactory.create(Bird::new); 7 bird.fly(); 8 // 生產一條魚 9 Animal fish = AnimalFactory.create(Fishe::new); 10 fish.swim(); 11 } 12 }
運行結果:
birds can fly...
fishes can swim......
3、介面靜態方法的“類優先”原則
如果一個介面實現類提供了具體的實現,那麼介面中具有相同名稱和參數的預設方法會被忽略,如改寫之前的Bird類:
1 public class Bird implements Animal { 2 3 public void fly() { 4 System.out.println("Bird類中的fly方法:birds can fly..."); 5 } 6 }
測試類:
1 public class TestMain { 2 3 public static void main(String[] args) { 4 5 Bird bird = new Bird(); 6 bird.fly(); 7 } 8 }
運行結果:
Bird類中的fly方法:birds can fly...
可見,調用的是Bird類中自己的fly()方法而不是Animal介面中的預設方法。
4、介面衝突
假如一個類實現了兩個介面,兩個介面中都有同樣的預設方法,哪個是有效的?
答案是:兩個都無效!
該類必須要覆該方法來解決衝突,否則編譯器將會報錯。