使用 default 关键字为接口定义默认方法(有实现的方法)
- 抽象方法,接口的子类需要实现
- 默认方法,接口的子类不需要实现,可以直接使用
- 可以定义一个或多个默认方法
使用:
public class InterfaceWithDefaultMethod {
public static void main(String[] args) throws Exception {
// 匿名类
MyInterface mi = new MyInterface() {
public void f1() {
System.out.println("f1");
}
};
mi.f1();
mi.f2(); // 子类可以直接使用默认方法
}
}
interface MyInterface {
void f1();
default void f2() {
System.out.println("f2");
}
}
接口的子类也可以实现默认方法,即重写(override)默认方法,例如:
public class InterfaceWithDefaultMethod {
public static void main(String[] args) throws Exception {
MyInterface mi = new MyInterface() {
public void f1() {
System.out.println("f1");
}
// 接口的子类也可以实现默认方法
public void f2() {
System.out.println("new f2");
}
};
mi.f1();
mi.f2();
}
}
interface MyInterface {
void f1();
default void f2() {
System.out.println("f2");
}
}
多重继承的问题
观察以下代码,会出现编译错误:
java: class InterfaceC inherits unrelated defaults for f() from types InterfaceA and InterfaceB
interface InterfaceA {
default void f() {}
}
interface InterfaceB {
default void f() {}
}
class InterfaceC implements InterfaceA, InterfaceB {
}
为了解决以上的冲突,需要手动重写(override)默认方法,例如:
class InterfaceC implements InterfaceA, InterfaceB {
public void f() {
System.out.println("my local f");
}
}
如果我们想使用特定接口的默认方法,可以使用如下方式:
class InterfaceC implements InterfaceA, InterfaceB {
public void f() {
InterfaceA.super.f();
}
}
Java库中的使用
Iterable<T> 接口中 forEach 方法即为默认方法,可以传入一个函数式接口,即 Lambda 表达式:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
抽象类 VS 接口(带有默认方法的接口)
相同点
- 都可以有方法实现(Java8 之前接口不能有方法实现)
- 子类不需要实现全部的方法(Java8 之前接口的子类需要实现全部的方法)
不同点
- 抽象类不可以多重继承,接口可以
- 抽象类表示的是"is-a"关系,接口表示的是"like-a"关系
- 接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能改变其值
- 抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值
引用:
Java 8 explained: Default Methods
Java 8新特性探究(二)深入解析默认方法