1.能力
為了更好地理解接口的好處以及在哪裡使用它們,我們需要談談一些更抽象的東西。
一個類通常模擬一個特定的對象。接口較少對應於對象,而更多地對應於它們的能力或角色。
例如,汽車、自行車、摩托車和車輪之類的東西最好表示為類和對象。但他們的能力——比如“我可以騎”、“我可以載人”、“我可以站立”——更好地呈現為界面。這裡有些例子:
代碼 | 描述 |
---|---|
|
對應移動能力 |
|
對應被騎的能力 |
|
對應於運輸東西的能力 |
|
類Wheel 可以移動 |
|
該類Car 可以移動、騎乘和運輸東西 |
|
班級Skateboard 可以移動和騎乘 |
2. 角色
接口極大地簡化了程序員的生活。通常,一個程序有數千個對象、數百個類,但只有幾十個接口,即角色。角色很少,但是有很多組合方式(類)。
重點是您不必在每個類中編寫代碼來與其他每個類進行交互。您只需要與他們的角色(接口)進行交互。
想像你是一名寵物訓練師。與您一起工作的每隻寵物都可以擁有多種不同的能力。您與鄰居就誰的寵物發出的噪音最大進行了友好的爭論。要解決這個問題,您只需將所有可以“說話”的寵物排成一行,然後給它們下達命令:說話!
你不關心他們是什麼動物,或者他們有什麼其他能力。即使他們可以做三重空翻。在這個特定的時刻,您只對他們大聲說話的能力感興趣。這是它在代碼中的樣子:
代碼 | 描述 |
---|---|
|
能力CanSpeak 。這個接口理解命令 to speak ,意味著它有相應的方法。 |
|
具有這種特徵的動物。
為了便於理解,我們提供了英文的類名。這在 Java 中是允許的,但這是非常不受歡迎的。
|
|
我們如何給他們命令? |
當你的程序中的類數量達到數千個時,你將無法沒有接口。不用描述幾千個類的交互,只描述幾十個接口的交互就夠了——這大大簡化了生活。
當與多態結合時,這種方法通常會取得巨大成功。
3.default
接口方法的實現
抽像類可以有變量和方法的實現,但不能有多重繼承。接口不能有變量或方法的實現,但可以有多重繼承。
情況如下表所示:
能力/財產 | 抽像類 | 接口 |
---|---|---|
變量 | ✔ | ✖ |
方法實現 | ✔ | ✖ |
多重繼承 | ✖ | ✔ |
所以,一些程序員真的希望接口能夠擁有方法實現。但是能夠添加一個方法實現並不意味著永遠都會添加一個。如果需要,請添加它。或者,如果你不這樣做,那就不要。
此外,多重繼承的問題主要是由變量引起的。無論如何,這就是他們的決定和所做的。從 JDK 8 開始,Java 引入了向接口添加方法實現的能力。
這是更新後的表格(適用於 JDK 8 及更高版本):
能力/財產 | 抽像類 | 接口 |
---|---|---|
變量 | ✔ | ✖ |
方法實現 | ✔ | ✔ |
多重繼承 | ✖ | ✔ |
現在對於抽像類和接口,您可以聲明帶有或不帶有實現的方法。這是個好消息!
在抽像類中,沒有實現的方法必須以abstract
關鍵字開頭。您無需在具有實現的方法之前添加任何內容。在接口中,情況正好相反。如果方法沒有實現,則不應添加任何內容。但是如果有實現的話,那麼就default
必須加上關鍵字。
為簡單起見,我們在下表中提供此信息:
能力/財產 | 抽像類 | 接口 |
---|---|---|
沒有實現的方法 | abstract |
– |
具有實現的方法 | – | default |
問題
使用具有方法的接口可以極大地簡化大型類層次結構。例如,抽象InputStream
和OutputStream
類可以聲明為接口!這讓我們可以更頻繁、更方便地使用它們。
但是世界上已經有數千萬(數十億?)Java 類。如果你開始改變標準庫,那麼你可能會破壞一些東西。喜歡一切!😛
為了不意外地破壞現有的程序和庫,決定接口中的方法實現具有最低的繼承優先級。
例如,如果一個接口繼承了另一個具有方法的接口,並且第一個接口聲明了相同的方法但沒有實現,那麼繼承接口的方法實現將不會到達繼承接口。例子:
interface Pet
{
default void meow()
{
System.out.println("Meow");
}
}
interface Cat extends Pet
{
void meow(); // Here we override the default implementation by omitting an implementation
}
class Tom implements Cat
{
}
該代碼將無法編譯,因為該類Tom
未實現該meow()
方法。
GO TO FULL VERSION