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

Java 为什么实现接口的抽象类会错过接口方法之一的声明/实现?,java,interface,abstract-class,Java,Interface,Abstract Class,在Java中,当您使用抽象类实现接口时,会发生一件奇怪的事情:接口的某些方法可能完全丢失,即既没有抽象声明也没有实际实现,但编译器不会抱怨 例如,给定接口: public interface IAnything { void m1(); void m2(); void m3(); } public interface IAnything { int i; void m1(); void m2(); void m3(); } 以下抽象类在没有警告或错误的情况下轻松编

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

例如,给定接口:

public interface IAnything {
  void m1();
  void m2();
  void m3();
}
public interface IAnything {
  int i;
  void m1();
  void m2();
  void m3();
}
以下抽象类在没有警告或错误的情况下轻松编译:

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

你能解释一下原因吗?

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

按照您的示例代码,尝试在不实现m2方法的情况下创建AbstractThing的子类,并查看编译器给您带来的错误。它将迫使您实现此方法。

非常好。 不能实例化抽象类。。但抽象类可用于容纳m1和m3的通用实现。 因此,如果m2实现对于每个实现是不同的,但m1和m3不是。您可以使用不同的m2实现创建不同的具体IAnything实现,并从AbstractThing中派生出来,这符合DRY原则。验证接口是否完全为抽象类实现是徒劳的


更新:有趣的是,我发现C将其作为编译错误强制执行。在这种情况下,您必须复制方法签名,并在抽象基类中使用“abstract public”作为前缀。。每天都有新东西:

实现这些方法不需要抽象类。因此,即使它实现了一个接口,接口的抽象方法也可以保持抽象。如果你试图在一个具体的类中实现一个接口,即非抽象类,而你没有实现抽象方法,编译器会告诉你:要么实现抽象方法,要么将类声明为抽象类。

接口指的是一个没有实现其方法的类,而只是声明。 另一方面,抽象类是一个类,它可以实现一些方法,也可以实现一些只声明而不实现的方法。
当我们实现抽象类的接口时,这意味着抽象类继承了接口的所有方法。因为,在抽象类中实现所有方法并不重要,但是它也是通过继承来实现抽象类的,所以抽象类可以在接口中留下一些方法而不在这里实现。但是,当这个抽象类被某个具体类继承时,它们必须实现抽象类中所有未实现的方法。

这很好。要理解上述内容,您必须首先理解抽象类的本质。在这方面,它们类似于接口。这就是甲骨文对此的说法

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

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

//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);
}
。。。正如您所看到的,这也编译得非常好。原因很简单,就像抽象类一样,接口不能实例化。因此,它不需要显式地提及其父级的方法。但是,所有父方法签名都隐式地成为扩展接口或实现抽象类的一部分。因此,一旦可以实例化的适当类扩展了上述内容,就需要确保实现每个抽象方法

希望这有助于。。。阿拉胡阿拉姆

当抽象类实现接口时

在关于接口的一节中,注意到 实现接口必须实现接口的所有方法。 但是,可以定义一个不实现所有功能的类 如果类声明为 摘要比如说,

在这种情况下,类X必须是抽象的,因为它不完全是抽象的 实现Y,但是类XX实际上实现Y

参考:

给定接口:

public interface IAnything {
  void m1();
  void m2();
  void m3();
}
public interface IAnything {
  int i;
  void m1();
  void m2();
  void m3();
}
Java实际上是这样看待它的:

public interface IAnything {
  public static final int i;
  public abstract void m1();
  public abstract void m2();
  public abstract void m3();
}
因此,您可以保留部分或所有这些抽象方法未实现,就像您在抽象类扩展另一个抽象类的情况下所做的那样

实现接口时,所有接口方法必须在派生类中实现的规则仅适用于具体的类实现,即它本身不是抽象的

如果您确实计划用它创建一个抽象类,那么没有规则说您必须实现所有接口方法。注意,在这种情况下,必须声明
作为抽象的派生类

我认为编译器仍然应该对未完全实现接口的抽象类发出警告,因为这样您就需要查看2个类定义,而不是1个,以查看子类中需要什么。但这是语言/编译器的限制。这不是一个好主意,因为通常会有很多抽象类,而“错误”警告很快就会淹没你,导致你错过“正确”警告。如果你仔细想想,“abstract”关键字专门用来告诉编译器取消对该类的警告。@workmad-如果您有接口方法子集的通用实现,那么将其分解到单独的基类中会更有意义,而不是一个地方代码,要求您在抽象类。如果您这样做,那么子类的实现者将继承这种非行为,而编译器不会告诉他们有问题。我认为workmad可能建议您在没有方法体的抽象类中定义方法,并将它们标记为抽象。对我来说似乎不是个坏主意。这是一个有趣的观点。它让我认为抽象类实际上是具体的接口,即带有一些具体方法的接口,而不是带有一些抽象方法的类。。。。两者兼而有之。但有一点可以肯定,它们是不可实例化的,不能创建抽象类的对象。因此,只要没有为抽象类提供实现,就无法为IAnything创建对象。所以这对于编译器来说是绝对好的。编译器希望,任何实现IAnything的非抽象类都必须实现在IAnything之外声明的所有方法。由于必须扩展和实现AbstractThing才能创建对象,如果该实现没有实现AbstractThing遗漏的IAnything方法,编译器将抛出一个错误。我有一个具体的类,它在与此相同的场景中扩展了自己的AbstractThing,尽管我没有在接口中实现其中一个方法,但它的编译过程令人费解。现在它正在做我期望的事情,但我不知道是什么原因导致了它以前的成功。我怀疑我没有:我有一个文件。您可以使用javap IAnything.class生成第二个代码段,看到类似问题的答案。