如果先在一个接口中将一个方法定义为默认方法,然后又在超类或另一个接口中定义了同样的方法,就会产生一个二义性错误.对于解决这个问题,java提供了相对简单的规则.
1)超类优先.如果超类提供了一个具体方法,同名并且有相同参数的默认方法会被忽略
2)接口冲突.如果一个接口提供了一个默认方法,另一个接口提供了一个同名而且参数类型相同的方法,必须覆盖这个方法来解决冲突
首先我们先看第二个规则:
//: 测试接口默认方法的冲突
interface Named {
default String getName() {
return getClass().getName() + "_" + hashCode() + " Named";
}
interface Base {
default String getName() {
return getClass().getName() + "_" + hashCode() + " Base";
}
}
public class Test implements Base, Named {
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.getName());
}
}
如上述代码所见,Test类同时实现了两个有同名且参数相同的默认方法的接口.编译后产生如下错误:
类会继承Base和Named接口提供的两个不一致的getName方法.并不是从中选择一个,java编译器会报告一个错误,让程序员来解决这个二义性.只需要在Test类中提供一个getName方法.在这个方法中,可以选择两个冲突方法中的一个,如下所示:
//: 测试接口默认方法的冲突
interface Named {
default String getName() {
return getClass().getName() + "_" + hashCode() + " Named";
}
}
interface Base {
default String getName() {
return getClass().getName() + "_" + hashCode() + " Base";
}
}
public class Test implements Base, Named {
//覆盖getName方法
public String getName() {
return Named.super.getName();
}
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.getName());
}
}
这样我们就能解决这个问题.
现在假设Named接口没有为getName提供默认实现:
Test类会从Base接口继承默认方法么?
//: 测试接口默认方法的冲突
interface Named {
String getName();
}
interface Base {
default String getName() {
return getClass().getName() + "_" + hashCode() + " Base";
}
}
public class Test implements Base, Named {
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.getName());
}
}
我们可以看到编译器依然还是报错.
java设计者强调一致性.两个接口如何冲突并不重要.如果至少一个接口提供了一个实现,编译器就会报告一个错误,而程序员就要解决这个个二义性.
当然,如果两个接口都没有为共享方法提供默认实现,这里就不存在冲突.实现类可以有两个选择:实现这个方法,或者干脆不实现.如果不实现,那么这个实现类本身就是抽象的.
现在来考虑另一种情况,一个类继承了一个超类,同时实现了一个接口,并从超类和接口继承了相同的方法.
//: 超类与接口方法冲突
interface Named {
default String getName() {
return getClass().getName() + "_" + hashCode() + " Named";
}
}
class Base {
public String getName() {
return getClass().getName() + "_" + hashCode() + " Base";
}
}
public class Test2 extends Base implements Named {
public static void main(String[] args) {
Test2 t = new Test2();
System.out.println(t.getName());
}
}
output:
在这种情况下,只会考虑超类方法,接口的所有默认方法都会被忽略.这正是”类优先”原则.
参考资料:corejava