有没有办法保证接口扩展Java中的类?

时间:2013-01-01 09:02:28

标签: java inheritance interface

假设我有以下情况:

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() { ... }
}

6 个答案:

答案 0 :(得分:26)

Java接口不能扩展类,这是有道理的,因为类包含无法在接口中指定的实现细节。

处理此问题的正确方法是将Vehicle转换为接口,从而将接口与实现完全分开。 Car e.t.c.可以扩展Vehicle接口以强制程序员实现相应的方法。如果要在所有Vehicle实例之间共享代码,则可以使用(可能是抽象的)类作为需要实现该接口的任何类的父类。

答案 1 :(得分:9)

您可以重新排列类和接口:

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

答案 2 :(得分:2)

这是一个奇怪的要求,但你可以使用泛型来完成某些事情:

<T extends MyInterface & MyAbstractClass>

答案 3 :(得分:1)

这个问题表明你没有掌握interfaceclass的本质。暂时忘记具体的Java语法,首先需要了解的是:接口是一组协议,应该是与实现无关的。让接口扩展一个类(面向实现)是没有意义的。

回到你的具体问题,如果你想保证Flier始终是一种Vehicle,只需将后者改为interface并让前者扩展它(它将一个协议扩展到另一个协议是否有意义)。之后,您可以创建任何实现VehicleFlier的类(抽象或具体)。

答案 4 :(得分:1)

如果你对Vehicle类有控制权,只需提取Vehicle作为接口,然后提供基础实现。

如果您无法控制Vehicle类,例如因为它是您正在使用的框架或第三方库的一部分,则无法用Java进行操作。

您可以做的最接近的事情是使用Generics多个通配符表示法。

<T extends Vehicle & Car>

但你不能直接将它直接应用于Car,除非你做这样的事情:

public interface Car<T extends Vehicle & Car>() {
    T self();
}

哪种机器人很奇怪,并没有强制实施自我实现方法,这只是一个强烈的提示/建议。

您可以像这样实施Car

public class CitroenC3 extends Vehicle implements Car<CitroenC3> {
    @Override
    public CitroenC3 self() {
        return this;
    }
}

可以像这样使用Car<?>

Car<?> car = obtainCarInSomeWay();
Vehicle v = car.self();
Car c = car.self();

它们应该都是有效的语法。

编译器在此强制执行的是您在Car<WHICH>中指定的内容,因为WHICH必须扩展Vehicle并实现Car。通过添加self(),您要向程序员说明T对象应该是对象本身,因此如果他希望符合规范,则强制通配符实例匹配该类。 / p> 在Java 8中,您甚至可以为self方法定义默认实现。

我也希望有更好的方法来处理这样的事情。

答案 5 :(得分:0)

  1. 定义新包
  2. 创建一个新的界面(即HiddenOne),范围为“default”,方法为“implementMe(HiddenOne)”
  3. 将车辆和飞行器移至新包裹。
  4. 从HiddenOne继承车辆和飞行器
  5. 在Vehicle中实施方法implementMe。
  6. 现在:每当您想要从“Flier”实施时,您必须从Vehicle 延伸! (因为只有车辆可以实施 implementMe )。

    这很棘手,但效果很好。