当您使用抽象类来实现接口时,Java中会发生奇怪的事情:某些接口的方法可能完全丢失(即既不存在抽象声明也不存在实际实现),但编译器不会抱怨.
例如,给定接口:
public interface IAnything { void m1(); void m2(); void m3(); }
以下抽象类在没有警告或错误的情况下快速编译:
public abstract class AbstractThing implements IAnything { public void m1() {} public void m3() {} }
你能解释一下原因吗?
那是因为如果一个类是抽象的,那么根据定义,你需要创建它的子类来实例化.子类将(由编译器)需要实现抽象类遗漏的任何接口方法.
按照您的示例代码,尝试在AbstractThing
不实现m2
方法的情况下创建子类,并查看编译器为您提供的错误.它会强制您实现此方法.
非常好.
您无法实例化抽象类..但是抽象类可用于容纳m1()和m3()的常见实现.
因此,如果每个实现的m2()实现不同,但m1和m3不是.您可以使用不同的m2实现创建不同的具体IAnything实现,并从AbstractThing派生 - 尊重DRY原则.验证接口是否完全为抽象类实现是徒劳的..
更新:有趣的是,我发现C#强制执行此编译错误.你被迫复制方法签名,并在这个场景中用抽象基类中的'abstract public'作为前缀..(每天都有新的东西:)
没关系.要理解上述内容,您必须首先了解抽象类的本质.它们在这方面类似于接口.这就是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'阿拉姆!