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()方法。