1. 程式人生 > 其它 >Java8新特性之四:介面預設方法和靜態方法

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

  public class Fish implements Animal {

  @Override

  public void swim() {

  System.out.println("fish can swim......");

  }

  @Override

  public void fly() {

  // donothing

  }

  }

  從上程式碼可以看到,因為Animal中定義了fly()和swim()方法,所以所有實現它的類都要覆寫這兩個方法,在Bird類中,鳥會飛,不會游泳,但是又必須要實現swim()方法,Fish類不會飛,但是又必須要實現fly()方法。程式碼出現冗餘。

  假如現在又有了新的需求,需要在Animal介面中再增加一個cry()方法,那麼之前所有實現了Animal介面的方法勢必都在再覆寫cry()方法,整個系統中可能會有很多地方需要同步修改,而此時,default方法和靜態方法就顯得尤為必要了。

  改寫上面的例子:

  Animal.java

  public interface Animal {

  default void fly() {

  System.out.println("birds can fly...");

  }

  default void swim() {

  System.out.println("fishes can swim......");

  }

  }

  Bird.java

  1 public class Bird implements Animal {

  2 }

  Fish.java

  1 public class Fish implements Animal {

  2 }

  測試類:

  public class TestMain {

  public static void main(String[] args) {

  Bird bird=new Bird();

  bird.fly();

  Fish fish=new Fishe();

  fish.swim();

  }

  }

  執行結果:

  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 supplier) {

  4 return supplier.get();

  5 }

  6 }

  測試類:

  public class TestAnimalFactory {

  public static void main(String[] args) {

  // 生產一隻鳥

  Animal bird=AnimalFactory.create(Bird::new);

  bird.fly();

  // 生產一條魚

  Animal fish=AnimalFactory.create(Fishe::new);

  fish.swim();

  }

  }

  執行結果:

  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 }

  測試類:

  public class TestMain {

  public static void main(String[] args) {

  Bird bird=new Bird();

  bird.fly();

  }

  }

  執行結果:

  Bird類中的fly方法:birds can fly...

  可見,呼叫的是Bird類中自己的fly()方法而不是Animal介面中的預設方法。

  4、介面衝突

  假如一個類實現了兩個介面,兩個介面中都有同樣的預設方法,哪個是有效的?

  答案是:兩個都無效!

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