接口和抽象类的区别(特别注意JDK8的接口可以有实现)
程序员文章站
2022-03-04 20:02:10
...
先来张图大致了解一下两者的区别:
注:接口中只能有static、final变量,不能有其他变量。表格中的一处错误:抽象类不能有default修饰符。
Java 8新特性–接口默认方法
默认方法是在接口中的方法签名前加上default关键字的实现方法。
/**
* 简单例子
*/
interface InterfaceA {
default void foo() {
System.out.println("InterfaceA foo");
}
}
class ClassA implements InterfaceA {
}
public class Test {
public static void main(String[] args) {
// 打印:“InterfaceA foo”
new ClassA().foo();
}
}
为什么要有默认方法?
在Java 8之前,接口与其实现类之间的耦合度过高(tightly coupled),当需要为一个接口添加方法时,所有的实现类都必须随之修改。默认方法可以为接口添加新的方法,而不会破坏已有的接口的实现。这在lambda表达式作为Java 8语言的重要特性出现之际,为升级旧接口且保持向后兼容(backward compatibility)提供了途径。
/**
* Iterable接口中的forEach默认方法
*/
public interface Iterable<T> {
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
}
默认方法的继承
接口默认方法的继承分三种情况(分别对应下面的InterfaceB接口、InterfaceC接口和InterfaceD接口):
- 不覆写默认方法,直接从父接口中获取方法的默认实现。
- 覆写默认方法,这跟类与类之间的覆写规则相类似。
- 覆写默认方法并将它重新声明为抽象方法,这样新接口的子类必须再次覆写并实现这个抽象方法。
interface InterfaceA {
default void foo() {
System.out.println("InterfaceA foo");
}
}
interface InterfaceB extends InterfaceA {
}
interface InterfaceC extends InterfaceA {
@Override
default void foo() {
System.out.println("InterfaceC foo");
}
}
interface InterfaceD extends InterfaceA {
@Override
void foo();
}
public class Test {
public static void main(String[] args) {
// 打印:“InterfaceA foo”
new InterfaceB() {}.foo();
// 打印:“InterfaceC foo”
new InterfaceC() {}.foo();
new InterfaceD() {
@Override
public void foo() {
// 打印:“InterfaceD foo”
System.out.println("InterfaceD foo");
}
}.foo();
// 或者使用lambda表达式
((InterfaceD) () -> System.out.println("InterfaceD foo")).foo();
}
}
Java 8新特性–接口静态方法
interface InterfaceA {
default void foo() {
printHelloWorld();
}
static void printHelloWorld() {
System.out.println("hello, world");
}
}
public class Test {
public static void main(String[] args) {
// 打印:“hello, world”
InterfaceA.printHelloWorld();
}
}
总结及注意点:default关键字只能在接口中使用(以及用在 switch语句的default分支),不能用在抽象类中;接口默认方法不能覆写Object类的equals、hashCode和toString方法;接口中的静态方法必须是public的,public修饰符可以省略,static修饰符不能省略。
下一篇: 线程的同步和死锁