interface 的设计初衷是面向抽象,提高扩展性。但缺点就是Interface 修改的时候,实现它的类也必须跟着修改。
为了解决接口的修改与现有的实现不兼容的问题。Java 8在接口声明的时候增加了两个新的概念:默认和静态方法。
新 interface 的方法可以用default 或 static修饰,一个 interface 中可以有多个方法被它们修饰,这 2 个修饰符的区别主要也是普通方法和静态方法的区别。
默认方法允许我们在接口里添加新的方法,而不会破坏实现这个接口的已有类的兼容性,也就是说不会强迫实现接口的类实现默认方法。
默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。作为替代方式,接口可以提供一个默认的方法实现,所有这个接口的实现类都会通过继承得到这个方法(如果有需要也可以重写这个方法)
我们来看一个实际的例子。
public interface InterfaceNew {
default void def() {
System.out.println("interface default方法");
}
}
public interface InterfaceNewImpl1 implements InterfaceNew{
}
public interface InterfaceNewImpl2 implements InterfaceNew{
public void def() {
System.out.println("interface InterfaceNewImpl2方法");
}
}
接口InterfaceNew使用default关键字声明了一个默认方法def(),类InterfaceNewImpl1实现了InterfaceNew接口,没有对默认方法做任何修改。另外一个类InterfaceNewImpl2重写类默认实现,提供了自己的实现方法。
Java 8 的另外一个有意思的新特性是接口里可以声明静态方法,并且可以实现。例子如下:
public interface InterfaceNew {
static void sm() {
System.out.println("interface提供的方式实现");
}
}
下面是把接口的静态方法和默认方法放在一起的示例:
public interface InterfaceNew {
default void def() {
System.out.println("interface default方法");
}
default void def2() {
System.out.println("interface default2方法");
}
static void sm() {
System.out.println("interface提供的方式实现");
}
static void sm2() {
System.out.println("interface提供的方式实现");
}
//需要实现类重写
void f();
}
public interface InterfaceNew1 {
default void def() {
System.out.println("InterfaceNew1 default方法");
}
}
如果有一个类既实现了 InterfaceNew 接口又实现了 InterfaceNew1接口,它们都有def(),并且 InterfaceNew 接口和InterfaceNew1接口没有继承关系的话,这时就必须重写def()。不然的话,编译的时候就会报错。
public class InterfaceNewImpl implements InterfaceNew , InterfaceNew1{
public static void main(String[] args) {
InterfaceNewImpl interfaceNew = new InterfaceNewImpl();
interfaceNew.def();
}
@Override
public void def() {
InterfaceNew1.super.def();
}
@Override
public void f() {
}
}
JVM平台的接口的默认方法实现是很高效的,并且方法调用的字节码指令支持默认方法。默认方法使已经存在的接口可以修改而不会影响编译的过程。java.util.Collection中添加的额外方法就是最好的例子:stream(), parallelStream(), forEach(), removeIf()
很多小伙伴认为:“既然 interface 也可以有自己的方法实现,似乎和 abstract class 没多大区别了。”
其实它们还是有区别的:
开始我们也提到,interface 新增default和static修饰的方法,为了解决接口的修改与现有的实现不兼容的问题,并不是为了要替代abstract class。在使用上,该用 abstract class 的地方还是要用 abstract class,不要因为 interface 的新特性而将之替换。
参考:
Java8 新特性实战 | JavaGuide(Java面试 + 学习指南)
Java 8 特性 – 终极手册 | 并发编程网 – ifeve.com