默认方法
在jdk8中关于接口新增一个特性,就是interface可以有默认方法。
例如定义一个Named接口:
public interface Named {
default String getName() {
return "nathan, by default";
}
}
假如你是1.8以下版本,这样写肯定连编译都通不过。可能有都同学会问,接口又不能实例化,增加这个方法都意义何在?在以往的java API中包含了很多伴随方法,如Collection/AbstractCollection,AbstractCollection实现了Collection中的部分方法。在jdk8中,就不需要这么做,直接使用default 关键字就能实现默认方法了,这样会使得代码结构更加精简。
现在我们来实现这个接口,定义一个NameNobody,但是不实现该方法:
public class NamedNobody implements Named {
}
接下来编写一个测试类:
public class Main {
public static void main(String[] args) {
Named named = new NamedNobody();
System.out.println(named.getName()); // nathan, by default
}
}
执行结果:
nathan, by default
可以看到即使没有实现接口方法,也会自动调用接口内的默认实现。
方法冲突
大家都知道,java是允许一个类同时实现多个接口的,现在有一个Person接口,也有一个getName方法
public interface Person {
default String getName() {
return "Person, by default";
}
}
然后有一个Student类同时实现了Person和Named接口
public class Student implements Named, Person {
@Override
public String getName() {
return "student";
}
}
此时Student必须实现getName方法,否则编译不通过。
public class Main {
public static void main(String[] args) {
Named student = new Student();
System.out.println(student.getName());
}
}
执行结果:
student
我们接下来看更一个更复杂的情况,有NamedPerson类,拥有一个getName方法
public class NamedPerson {
public String getName() {
return "NamedPerson";
}
}
还有个Staff类,继承了NamedPerson,实现了Named接口
public class Staff extends NamedPerson implements Named {
}
此时不实现Named中的抽象方法也不会报错,我们来运行以下看看:
public class Main {
public static void main(String[] args) {
Staff staff = new Staff();
System.out.println(staff.getName());
}
}
执行结果:
NamedPerson
可以看到实际调用的是父类中的方法。
上图是整个demo的继承关系。
通过上面两个例子,我们可以总结出两条解决冲突的规则:
- 接口冲突:如果一个类同时实现了具有相同方法签名的接口,则该类必须覆盖该抽象方法。
- 超类冲突:超类和接口提供相同方法签名的方法,此时子类要是不覆盖,则默认调用超类方法。