最近突然想到一個老生常談的問題:爲什麼Java的類不支持多繼承(接口支持的哈)?
拋開高司令不想搞得太複雜的說法,大概答案就是
- 若子類繼承的多個父類擁有相同的成員變量,子類在引用該變量時將無法判別使用哪個父類的成員變量。
- 若子類繼承的多個父類擁有相同的方法,同時子類並未覆蓋該方法(若覆蓋,則直接使用子類中該方法),那麼調用該方法時將無法確定調用哪個父類的方法。
那麼一個類實現了多個接口,就沒有這個問題了嗎?
在Java 8之前,很容易解釋
- 接口定義的變量都是常量,編譯時就確定調用關係,使用接口名可以避免歧義。
- 方法調用時始終只會調用實現類的方法,不存在歧義。
不過,Java 8之後接口可以擁有默認方法,一個類實現的多個接口具有相同的默認方法咋辦咧?
沒辦法,只能要求子類做出選擇了(重寫該方法)。
相關代碼證明
/**
* 一個類實現的多個接口具有相同簽名的方法
*
* @author Zhou Huanghua
*/
public class T implements A, B {
public static void main(String[] args) {
int i = A.CONSTANT; // 使用T.CONSTANT不能通過編譯
A a = new T();
a.m1(); // 打印T#m1
a.m2(); // 打印B#m2
B b = new T();
b.m2(); // 打印B#m2
T t = new T();
t.m2();// 打印B#m2
}
@Override
public void m1() {
System.out.println("T#m1");
}
/**
* 必須重寫,否則編譯失敗
*/
@Override
public void m2() {
// 調用B的方法
B.super.m2();
}
}
interface A {
int CONSTANT = 1;
void m1();
default void m2() {
System.out.println("A#m2");
}
}
interface B {
int CONSTANT = 2;
void m1();
default void m2() {
System.out.println("B#m2");
}
}
/**
* 接口支持多繼承,如果有相同的默認方法必須重寫
*/
interface C extends A, B {
@Override
default void m2() {
A.super.m2();
}
}