134

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

例如,给定接口:

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

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

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

你能解释一下为什么吗?

4

7 回答 7

167

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

按照您的示例代码,尝试在AbstractThing不实现该m2方法的情况下创建一个子类,并查看编译器给您带来的错误。它会强制你实现这个方法。

于 2008-10-13T15:04:48.110 回答
34

完全没问题。
你不能实例化抽象类。但抽象类可用于容纳 m1() 和 m3() 的常见实现。
因此,如果每个实现的 m2() 实现不同,但 m1 和 m3 则不同。您可以使用不同的 m2 实现创建不同的具体 IAnything 实现,并从 AbstractThing 派生——尊重 DRY 原则。验证接口是否为抽象类完全实现是徒劳的。

更新:有趣的是,我发现 C# 将其强制为编译错误。在这种情况下,您被迫复制方法签名并在抽象基类中为它们加上“abstract public”前缀..(每天都有新的东西:)

于 2008-10-13T15:19:19.500 回答
7

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

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

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

//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'alam!

于 2015-04-09T02:46:49.350 回答
4

接口是指没有实现其方法但只有声明的类。
另一方面,抽象类是一个可以实现某些方法以及某些方法的类,只有声明,没有实现。
当我们实现一个抽象类的接口时,意味着抽象类继承了该接口的所有方法。因为,在抽象类中实现所有方法并不重要,但是它涉及到抽象类(也通过继承),因此抽象类可以将接口中的一些方法留在此处而无需实现。但是,当这个抽象类将被某个具体类继承时,他们必须在抽象类中实现所有那些未实现的方法。

于 2013-10-08T01:20:40.583 回答
4

给定接口:

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();
}

因此,您可以保留这些abstract方法中的一些(或全部)未实现,就像在abstract类扩展另一个abstract类的情况下所做的那样。

当您implement使用interface时,所有interface方法都必须在派生中实现的规则class仅适用于具体class实现(即,它本身不是abstract)。

如果您确实打算从中创建一个abstract class,那么没有规则说您拥有implement所有interface方法(请注意,在这种情况下,必须将派生声明classabstract

于 2017-08-12T03:49:44.133 回答
3

当抽象类实现接口时

在接口部分中,注意到实现接口的类必须实现接口的所有方法。但是,可以定义一个不实现所有接口方法的类,前提是该类被声明为抽象类。例如,

abstract class X implements Y {   
    // implements all but one method of Y
}

class XX extends X {   
    // implements the remaining method in Y 
} 

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

参考:http ://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

于 2016-10-29T15:43:49.810 回答
1

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

于 2008-10-13T15:21:39.590 回答