当您使用抽象类来实现接口时,Java中会发生奇怪的事情:某些接口的方法可能完全丢失(即既不存在抽象声明也不存在实际实现),但编译器不会抱怨。
例如,给定接口:
public interface IAnything {
void m1();
void m2();
void m3();
}
以下抽象类在没有警告或错误的情况下快速编译:
public abstract class AbstractThing implements IAnything {
public void m1() {}
public void m3() {}
}
你能解释一下原因吗?
答案 0 :(得分:148)
那是因为如果一个类是抽象的,那么根据定义,你需要创建它的子类来实例化。子类(由编译器)将需要实现抽象类遗漏的任何接口方法。
按照您的示例代码,尝试创建AbstractThing
的子类,而不实现m2
方法,并查看编译器为您提供的错误。它会强制你实现这个方法。
答案 1 :(得分:33)
非常好。
您不能实例化抽象类..但是抽象类可用于容纳m1()和m3()的常见实现。
所以如果 m2()实现对于每个实现都不同,但m1和m3不是。您可以使用不同的m2实现创建不同的具体IAnything实现,并从AbstractThing派生 - 尊重DRY原则。验证接口是否完全为抽象类实现是徒劳的..
更新:有趣的是,我发现C#将此作为编译错误强制执行。你被迫复制方法签名,并在这个场景中用抽象基类中的'abstract public'作为前缀。(每天都有新的东西:)
答案 2 :(得分:7)
没关系。要理解上述内容,您必须首先了解抽象类的本质。它们在这方面类似于接口。这就是Oracle对此here所说的话。
抽象类与接口类似。您无法实例化它们,并且它们可能包含使用或不使用实现声明的方法组合。
所以你必须考虑当接口扩展另一个接口时会发生什么。例如......
//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!
答案 3 :(得分:4)
接口是指一个没有实现其方法的类,但只是声明 另一方面,抽象类是一个可以实现某种方法的类,以及一些只有声明的方法,没有实现 当我们实现抽象类的接口时,它意味着抽象类继承了接口的所有方法。因为,在抽象类中实现所有方法并不重要,但它涉及抽象类(通过继承),因此抽象类可以在接口中保留一些方法而不在此实现。但是,当这个抽象类将由一些具体类继承时,它们必须在抽象类中实现所有那些未实现的方法。
答案 4 :(得分:2)
抽象类实现接口时
在接口部分,有人注意到一个类 实现接口必须实现所有接口的方法。 但是,可以定义一个不实现所有的类 接口的方法,只要声明该类 抽象。例如,
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
答案 5 :(得分:1)
实现这些方法不需要抽象类。因此即使它实现了一个接口,接口的抽象方法也可以保持抽象。如果您尝试在具体类中实现接口(即不是抽象),并且您没有实现抽象方法,编译器将告诉您:实现抽象方法或将类声明为抽象。