Java8新特性之四:接口默認方法和靜態方法


  在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、接口沖突

  假如一個類實現了兩個接口,兩個接口中都有同樣的默認方法,哪個是有效的?

  答案是:兩個都無效!

  該類必須要覆該方法來解決沖突,否則編譯器將會報錯。

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM