接口繼承
一個interface
可以繼承自另一個interface
。interface
繼承自interface
使用extends
,它相當於擴展了接口的方法。例如:
interface Hello {
void hello();
}
interface Person extends Hello {
void run();
String getName();
}
此時,Person
接口繼承自Hello
接口,因此,Person
接口現在實際上有3個抽象方法簽名,其中一個來自繼承的Hello
接口。
繼承關係
合理設計interface
和abstract class
的繼承關係,可以充分複用代碼。一般來說,公共邏輯適合放在abstract class
中,具體邏輯放到各個子類,而接口層次代表抽象程度。可以參考Java的集合類定義的一組接口、抽象類以及具體子類的繼承關係:
──────────────┐
│ Iterable │
└───────────────┘
▲ ┌───────────────────┐
│ │ Object │
┌───────────────┐ └───────────────────┘
│ Collection │ ▲
└───────────────┘ │
▲ ▲ ┌───────────────────┐
│ └──────────│AbstractCollection │
┌───────────────┐ └───────────────────┘
│ List │ ▲
└───────────────┘ │
▲ ┌───────────────────┐
└──────────│ AbstractList │
└───────────────────┘
▲ ▲
│ │
│ │
┌────────────┐ ┌────────────┐
│ ArrayList │ │ LinkedList │
└────────────┘ └────────────┘
在使用的時候,實例化的對象永遠只能是某個具體的子類,但總是通過接口去引用它,因爲接口比抽象類更抽象:
List list = new ArrayList(); // 用List接口引用具體子類的實例
Collection coll = list; // 向上轉型爲Collection接口
Iterable it = coll; // 向上轉型爲Iterable接口
default方法
在接口中,可以定義default
方法。例如,把Person
接口的run()
方法改爲default
方法:
public class Main {
public static void main(String[] args) {
Person p = new Student("Xiao Ming");
p.run();
}
}
interface Person {
String getName();
default void run() {
System.out.println(getName() + " run");
}
}
class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
實現類可以不必覆寫
default
方法。default
方法的目的是,當我們需要給接口新增一個方法時,會涉及到修改全部子類。如果新增的是
default
方法,那麼子類就不必全部修改,只需要在需要覆寫的地方去覆寫新增方法。
default
方法和抽象類的普通方法是有所不同的。因爲
interface
沒有字段,default
方法無法訪問字段,而抽象類的普通方法可以訪問實例字段。