1.能力

為了更好地理解接口的好處以及在哪裡使用它們,我們需要談談一些更抽象的東西。

一個類通常模擬一個特定的對象。接口較少對應於對象,而更多地對應於它們的能力或角色。

接口的本質

例如,汽車、自行車、摩托車和車輪之類的東西最好表示為類和對象。但他們的能力——比如“我可以騎”、“我可以載人”、“我可以站立”——更好地呈現為界面。這裡有些例子:

代碼 描述
interface CanMove
{
   void move(String newLocation);
}
對應移動能力
interface Rideable
{
   void ride(Passenger passenger);
}
對應被騎的能力
interface CanTransport
{
   void addStuff(Object stuff);
   Object removeStuff();
}
對應於運輸東西的能力
class Wheel implements CanMove
{
   ...
}
Wheel可以移動
class Car implements CanMove, Rideable, CanTransport
{
   ...
}
該類Car可以移動、騎乘和運輸東西
class Skateboard implements CanMove, Rideable
{
   ...
}
班級Skateboard可以移動和騎乘


2. 角色

接口極大地簡化了程序員的生活。通常,一個程序有數千個對象、數百個類,但只有幾十個接口,即角色。角色很少,但是有很多組合方式(類)。

重點是您不必在每個類中編寫代碼來與其他每個類進行交互。您只需要與他們的角色(接口)進行交互。

想像你是一名寵物訓練師。與您一起工作的每隻寵物都可以擁有多種不同的能力。您與鄰居就誰的寵物發出的噪音最大進行了友好的爭論。要解決這個問題,您只需將所有可以“說話”的寵物排成一行,然後給它們下達命令:說話!

你不關心他們是什麼動物,或者他們有什麼其他能力。即使他們可以做三重空翻。在這個特定的時刻,您只對他們大聲說話的能力感興趣。這是它在代碼中的樣子:

代碼 描述
interface CanSpeak
{
   void speak();
}
能力CanSpeak。這個接口理解命令 to speak,意味著它有相應的方法。
class Cat implements CanSpeak
{
   void speak()
   {
      println("MEOW");
   }
}

class Dog implements CanSpeak
{
   void speak()
   {
      println("WOOF");
   }
}

class Fish
{
   ...
}
具有這種特徵的動物。

為了便於理解,我們提供了英文的類名。這在 Java 中是允許的,但這是非常不受歡迎的。













我們Fish沒有說話的能力(不實現接口CanSpeak)。

public static void main(String[] args)
{
   // Add all the animals to the list
   ArrayList pets = new ArrayList();
   pets.add(new Cat());
   pets.add(new Dog());
   pets.add(new Fish());

   // If the ability exists, then make a sound
   for(Object pet: pets)
   {
      if (pet instanceof CanSpeak)
      {
         CanSpeak loudmouth = (CanSpeak) pet;
         loudmouth.speak();
      }
   }
}
我們如何給他們命令?

當你的程序中的類數量達到數千個時,你將無法沒有接口。不用描述幾千個類的交互,只描述幾十個接口的交互就夠了——這大大簡化了生活。

當與多態結合時,這種方法通常會取得巨大成功。



3.default接口方法的實現

抽像類可以有變量和方法的實現,但不能有多重繼承。接口不能有變量或方法的實現,但可以有多重繼承。

情況如下表所示:

能力/財產 抽像類 接口
變量
方法實現
多重繼承

所以,一些程序員真的希望接口能夠擁有方法實現。但是能夠添加一個方法實現並不意味著永遠都會添加一個。如果需要,請添加它。或者,如果你不這樣做,那就不要。

此外,多重繼承的問題主要是由變量引起的。無論如何,這就是他們的決定和所做的。從 JDK 8 開始,Java 引入了向接口添加方法實現的能力。

這是更新後的表格(適用於 JDK 8 及更高版本):

能力/財產 抽像類 接口
變量
方法實現
多重繼承

現在對於抽像類和接口,您可以聲明帶有或不帶有實現的方法。這是個好消息!

在抽像類中,沒有實現的方法必須以abstract關鍵字開頭。您無需在具有實現的方法之前添加任何內容。在接口中,情況正好相反。如果方法沒有實現,則不應添加任何內容。但是如果有實現的話,那麼就default必須加上關鍵字。

為簡單起見,我們在下表中提供此信息:

能力/財產 抽像類 接口
沒有實現的方法 abstract
具有實現的方法 default

問題

使用具有方法的接口可以極大地簡化大型類層次結構。例如,抽象InputStreamOutputStream類可以聲明為接口!這讓我們可以更頻繁、更方便地使用它們。

但是世界上已經有數千萬(數十億?)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()方法。