有没有办法保证接口扩展Java中的类?
假设我有以下情况:
public abstract class Vehicle { public void turnOn() { ... } } public interface Flier { public void fly(); }
有没有办法可以保证任何实现Flier
类都必须扩展Vehicle
? 我不想让Flier
成为一个抽象类,因为我希望能够以类似的方式混合其他一些接口。
例如:
// I also want to guarantee any class that implements Car must also implement Vehicle public interface Car { public void honk(); } // I want the compiler to either give me an error saying // MySpecialMachine must extend Vehicle, or implicitly make // it a subclass of Vehicle. Either way, I want it to be // impossible to implement Car or Flier without also being // a subclass of Vehicle. public class MySpecialMachine implements Car, Flier { public void honk() { ... } public void fly() { ... } }
Java接口不能扩展类,这是有道理的,因为类包含无法在接口中指定的实现细节。
解决此问题的正确方法是通过将Vehicle
转换为接口来完全将接口与实现分开。 Car
等可以扩展Vehicle
界面,迫使程序员实现相应的方法。 如果要在所有Vehicle
实例之间共享代码,则可以使用(可能是抽象的)类作为需要实现该接口的任何类的父类。
您可以重新排列类和接口,如下所示:
public interface IVehicle { public void turnOn(); } public abstract class Vehicle implements IVehicle { public void turnOn() { ... } } public interface Flier extends IVehicle { public void fly(); }
这样, Flier
所有实现都保证实现车辆的协议 ,即IVehicle
。
这是一个奇怪的要求,但你可以使用generics完成某些事情:
这个问题表明你还没有掌握interface
和class
的本质。 暂时忘记具体的Java语法,首先需要了解的是:接口是一组协议,应该是与实现无关的。 让接口扩展一个类(面向实现)是没有意义的。
回到你的具体问题,如果你想保证Flier
总是一种Vehicle
,只需将后者改为一个interface
,让前者扩展它(从另一个协议扩展一个协议是有意义的)。 之后,您可以创建任何实现Vehicle
或Flier
类(抽象或具体)。
如果您对Vehicle
类具有控制权,则只需将Vehicle
作为接口提取,然后提供基本实现。
如果您无法控制Vehicle
类,例如因为它是您正在使用的框架或第三方库的一部分,则无法使用Java。
您可以做的最接近的事情是使用Generics多个通配符表示法。
但你不能直接将它直接应用于Car,除非你做这样的事情:
public interface Car() { T self(); }
这是机器人很奇怪,并没有强制自我方法来实际返回自我,这只是一个强烈的提示/建议。
你会像这样实现一辆Car
:
public class CitroenC3 extends Vehicle implements Car { @Override public CitroenC3 self() { return this; } }
一个人可以像这样使用Car>
:
Car> car = obtainCarInSomeWay(); Vehicle v = car.self(); Car c = car.self();
它们应该都是有效的语法。
编译器在此强制执行的是您在Car
指定的内容必须同时扩展Vehicle
并实现Car
。 通过添加self()
您向程序员说, T
对象应该是对象本身,因此如果他想要符合规范,则强制通配符实例匹配该类。
在Java 8中,您甚至可以为self方法定义默认实现。
我也希望有更好的方法来处理这样的事情。
- 定义一个新包
- 创建一个新的接口(即HiddenOne),其范围为“default”,方法为“implementMe(HiddenOne)”
- 将Vehicle and Flier移动到新包。
- 从HiddenOneinheritance车辆和飞行器
- 在Vehicle中实现方法implementMe。
现在:无论何时你想从“Flier”实施,你必须从车辆延伸! (因为只有Vehicle可以实现implementMe )。
这很棘手,但效果很好。