2013-01-01 64 views
19

假设我有以下情况:有没有一种方法可以保证一个接口在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() { ... } 
} 
+0

接口扩展接口。 (摘要)类(部分)实现接口并扩展其他类。 – asgs

+0

试试我的建议,你无法编译MySpecialMachine而不从车辆延伸! –

回答

22

Java接口不能扩展类,这是有道理的,因为类包含不能在一个界面中进行规定实施细则..

正确的方式来处理这个问题是通过将Vehicle也变成一个接口,完全将接口与实施分开。 Car e.t.c.可以扩展接口强制程序员实现相应的方法。如果您想在所有Vehicle实例中共享代码,那么您可以使用(可能是抽象的)类作为需要实现该接口的任何类的父代。

+0

如果他不能实现对应的方法?如果只有Vehicle可以实现相应的方法?想一想。 –

+0

@PeterRader:我不明白你在做什么。他*已经*在'Vehicle'中实现了这些方法。他所要做的就是将'Vehicle'变成一个接口,并在必要时将任何实现细节移至抽象基类... – thkala

+0

车辆已经是一个抽象基类。 –

8

你可以重新安排你的类和接口是这样的:的Flier

public interface IVehicle { 
    public void turnOn(); 
} 

public abstract class Vehicle implements IVehicle { 
    public void turnOn() { ... } 
} 

public interface Flier extends IVehicle { 
    public void fly(); 
} 

这样,所有的实现都保证实现协议车辆的,即IVehicle

+1

一个小小的挑剔 - 如果要使用'I *'约定(其中,顺便说一句,从来没有像我这样的Java-y),那么它应该用于* all *接口... – thkala

+0

@thkala:是的, 'I *'约定主要是一个.NET事物。我用它是因为我需要与'Vehicle'不同但相关的名字。清理名称以确保命名一致将有所帮助。 – Codo

1

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

回到你的具体问题,如果你想保证一个Flier始终是一种Vehicle,只是改变了后者的interface,让前将其扩展(这有一定道理,从其他协议延长一个协议)。之后,您可以创建任何实施VehicleFlier的课程(抽象或具体)。

+0

这可能是这种情况,但操作系统可能会使用一个外部框架,其中'Vehicle'是一个类(即使它应该是一个接口)。 –

2

这是一个奇怪的要求,但你可以完成类似的东西与泛型:(即HiddenOne)

<T extends MyInterface & MyAbstractClass> 
0
  1. 定义一个新包
  2. 创建一个新的接口范围“默认”用一个方法“implementsMe(HiddenOne)”
  3. 移动车辆和飞行器到新的包。
  4. 从HiddenOne继承车辆和飞行器
  5. 在Vehicle中实现方法implement制器。

现在:,只要你喜欢,从“新干线”的实施,必须从汽车延伸! (因为只有汽车可以实现implementMe)。

这是棘手,但伟大工程。

+0

还有一个使用受保护的内部类的更复杂的解决方案。 –

+0

如果有人在这个新软件包中创建了一个Submarine类,该怎么办?然后,他们可以直接执行'HiddenOne',而无需通过'Vehicle' ... – thkala

+0

您可以使用安全规则保护您的包裹。但是......好的,受保护的内部类可能更容易。 –

1

如果您对Vehicle类控制只是提取Vehicle为一个接口,然后提供一个基本的实现。

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

你可以使用泛型多个通配符符号做最接近的事。

<T extends Vehicle & Car> 

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

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

这是BOT怪异和不执行自方法实际上返回自我,这只是强烈的暗示/建议。

你会实现一个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>中指定的内容,它们必须同时扩展为Vehicle并实现Car。并且通过添加self(),您对程序员说,T对象本身应该是对象,因此如果想要符合规范,则强制通配符实例匹配该类。

在Java中8你甚至可以定义为自方法的默认实现。

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

相关问题