具有泛型方法的泛型类的协方差

时间:2018-03-19 20:12:09

标签: java generics inheritance covariance

当在泛型类上使用协方差时,我无法正确定义泛型方法,如果这是我想要的方式。我最好通过例子来解释手头的问题。

假设我们有以下汽车接口设置

interface Car { ... }
interface SportsCar extends Car { ... }

和汽车供应商返回Sale对象

的通用接口
interface CarVendor<C extends Car> {    
  Sale<C> sell(C car);
}

interface SportsCarVendor extends CarVendor<SportsCar> {    
  @Override
  Sale<SportsCar> sell(SportsCar car);
}

现在我们假设我们希望我们的汽车是通用的,例如关于燃料类型:

interface Car<F extends FuelType> { ... }
interface SportsCar<F extends FuelType> extends Car<F> { ... }
class PetrolSportsCar extends SportsCar<Petrol> { ... }
class DieselSportsCar extends SportsCar<Diesel> { ... }

如果我们不想为任何燃料销售汽车,我们在重新定义供应商界面时会遇到问题。通用方法似乎是答案,但我无法正确定义它,因为在类上定义了通用Car<?>,但应在方法上定义通用FuelType。得到这个想法:

interface CarVendor<C extends Car<?>> {
  <F extends FuelType> Sale<Car<F>> sell(Car<F> param);
}

interface SportsCarVendor extends CarVendor<SportsCar<?>> {
  @Override 
  <F extends FuelType> Sale<SportsCar<F>> sell(SportsCar<F> param);
}
由于签名SportsCarVendor与预期类型sell(SportsCar<F>)不匹配,

SportsCar<?>显然无法编译。

有人可以为这个问题提供可行的解决方案吗?

2 个答案:

答案 0 :(得分:3)

从目前为止提供的内容来看,我没有看到任何理由为什么大多数接口和类应该是通用的,并且我看到为什么大多数不应该是通用的原因。

FuelType听起来应该是Car属性,而不是类型参数。也许它可以声明为枚举,具体取决于您的具体要求。

enum FuelType {
    PETROL,
    DIESEL;
}

public class Car {
    private FuelType fuelType;
    // rest of implementation
}

同样,Car应该是Sale的属性,而不是类型参数。

public class Sale {
    private Car sold;
    // rest of implementation
}

您可能仍然需要SportsCarVendor是通用的,以便您可以缩小实施类可以销售的car类型,但Sale sell方法仍会返回不需要是通用的。

interface CarVendor<C extends Car> {    
    Sale sell(C car);
}

interface SportsCarVendor extends CarVendor<SportsCar> {    
    @Override
    Sale sell(SportsCar car);
}

此外,如果您碰巧需要Sale的特定子类,例如SportsCarSale,那么你可以使用return-type covariance,这是一个子类在没有泛型的情况下缩小返回类型的能力:

interface SportsCarVendor extends CarVendor<SportsCar> {    
    @Override
    SportsCarSale sell(SportsCar car);
}

答案 1 :(得分:0)

如果您真的必须为每个汽车供应商单独处理燃料类型(可能是税务原因?),您可以通过以下方式定义汽车供应商以实现此目的:

interface CarVendor<F extends FuelType, C extends Car<F>> {
    Sale<C> sell(C param);
}

interface SportsCarVendor <F extends FuelType> extends CarVendor<F, SportsCar<F>> { }

现在具体实现:

class SportsCarVendorDiesel implements SportsCarVendor<DieselFuel> {
    @Override
    public Sale<SportsCar<DieselFuel>> sell(SportsCar<DieselFuel> param) {
        return null;
    }
}

class SportsCarVendorGas implements SportsCarVendor<GasolineFuel> {
    @Override
    public Sale<SportsCar<GasolineFuel>> sell(SportsCar<GasolineFuel> param) {
        return null;
    }
}

我使用的其他类都是这样的:

interface FuelType {
    double burnRate();
}

class DieselFuel implements FuelType {

    @Override
    public double burnRate() {
        return 0;
    }
}

class GasolineFuel implements FuelType {

    @Override
    public double burnRate() {
        return 0;
    }
}

interface Car<F extends FuelType> { }
interface SportsCar<F extends FuelType> extends Car<F> { }

class Sale<C> { }