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、接口冲突
假如一个类实现了两个接口,两个接口中都有同样的默认方法,哪个是有效的?
答案是:两个都无效!
该类必须要覆该方法来解决冲突,否则编译器将会报错。