接口的默认方法
Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用 default 关键字修饰。
public interface MyFun {
default String getName(){
return "小李";
}
}
类优先原则
若一个接口中定义了一个默认方法,而另外一个父类中又定义了一个同名的方法时,继承的子类会选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
定义一个父类同样具有getName方法
public class MyClass {
public String getName(){
return "小王";
}
}
定义一个实现类继承MyClass实现MyFun
public class FunImpl extends MyClass implements MyFun{
// 父类MyClass中getName方法有实现了 在子类中默认会忽略
}
测试getName
FunImpl fun = new FunImpl();
System.out.println(fun.getName());// 打印小王
如果一个子类实现了两个接口,一个父接口中提供了一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法) ,那么必须覆盖该方法来解决冲突。
在定义一个接口同样具有getName方法
public interface MyInterface {
default String getName(){
return "小张";
}
}
定义一个实现类实现这两个接口,会提示你必须选择一个接口重写方法
随便选择一个试试
public class FunImpl2 implements MyFun,MyInterface{
@Override
public String getName() {
// TODO Auto-generated method stub
return MyInterface.super.getName();
}
}
测试
FunImpl2 fun2 = new FunImpl2();
System.out.println(fun2.getName());// 小张
另外,当实现的接口的父接口中也有同样的默认方法时,就近原则调用子接口的方法。
定义一个接口继承MyFun接口并定义一个默认方法
public interface SubInterface extends MyFun{
default String getName(){
return "小刘";
}
}
定义一个实现类实现SubInterface和MyFun
public class FunImpl3 implements SubInterface,MyFun{
}
测试
FunImpl3 fun3 = new FunImpl3();
System.out.println(fun3.getName());// 小刘
默认方法的优势
默认方法主要优势是提供了一种扩展接口的方法,而不破坏现有代码。如果一个已经投入使用的接口需要扩展一个新的方法,在JDK8以前,我们必须再该接口的所有实现类中都添加该方法的实现,否则编译会出错。如果实现类数量很少且我们有修改的权限,可能工作量会少,但是如果实现类很多或者我们没有修改代码的权限,这样的话就很难解决了。而默认方法提供了一个实现,当没有显式提供时就默认采用这个实现,这样新添加的接口就不会破坏现有的代码。
默认方法另一个优势是该方法是可选的,子类可以根据不同的需求而且经override或者采用默认实现。例如我们定义一个集合几口,其中有增、删、改等操作,如果我们的实现类90%都是以数组保存数据,那么我们可以定义针对这些方法给出默认实现,而对于其他非数组集合或者有其他类似业务,可以选择性复写接口中默认方法。
接口的静态方法
Java8 中,接口中允许添加静态方法。
public interface MyFun {
default String getName(){
return "小李";
}
public static void showName(){
System.out.println("小李");
}
}
在调用静态方法时,不需要实现接口,也不需要接口的实例,调用方式依然是类名.方法名
MyFun.showName();
注意:实现接口的类或者子接口不会继承接口中的静态方法。static不能和default同时使用。