为什么实现接口的抽象类可能会错过接口方法之一的声明/实现?

问题

当你使用抽象类来实现接口时,Java中会发生一件奇怪的事情:某些接口的方法可能完全丢失(即既不存在抽象声明也不存在实际实现),但编译器不会抱怨。

例如,给定接口:

public interface IAnything {
  void m1();
  void m2();
  void m3();
}

以下抽象类在没有警告或错误的情况下快速编译:

public abstract class AbstractThing implements IAnything {
  public void m1() {}
  public void m3() {}
}

你能解释一下原因吗?


#1 热门回答(140 赞)

那是因为如果一个类是抽象的,那么根据定义,你需要创建它的子类来实例化。子类将(由编译器)需要实现抽象类遗漏的任何接口方法。

按照你的示例代码,尝试创建一个AbstractThing的子类,而不实现m2方法,并查看编译器给你的错误。它会强制你实现此方法。


#2 热门回答(31 赞)

非常好。
你无法实例化抽象类..但是抽象类可用于容纳m1()和m3()的常见实现。
Soifm2()实现对于每个实现是不同的,但是m1和m3不是。你可以使用不同的m2实现创建不同的具体IAnything实现,并从AbstractThing派生 - 尊重DRY原则。验证接口是否完全为抽象类实现是徒劳的..

更新:有趣的是,我发现C#将此作为编译错误强制执行。你被迫复制方法签名,并在这个场景中用抽象基类中的'abstract public'作为前缀..(每天都有新的东西:)


#3 热门回答(5 赞)

没关系。要理解上述内容,首先必须了解抽象类的本质。它们在这方面类似于接口。这就是Oracle对thishere所说的话。

抽象类与接口类似。你无法实例化它们,并且它们可能包含使用或不使用实现声明的混合方法。

因此,你必须考虑当接口扩展另一个接口时会发生什么。例如 ...

//Filename: Sports.java
public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}

//Filename: Football.java
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}

......正如你所看到的,这也很好地编译。仅仅因为,就像抽象类一样,接口无法实例化。因此,不需要从其"父"明确提及方法。但是,所有父方法签名都隐式地成为扩展接口或实现抽象类的一部分。因此,一旦适当的类(可以实例化的类)扩展了上述内容,就需要确保实现每个抽象方法。

希望有助于......和Allahu'阿拉姆!