使用泛型类和泛型方法的协变性

4

如果我打算在泛型类上使用协变,我就无法正确定义泛型方法。为了更好地解释问题,请看以下示例。

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

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<?>不匹配。

有人能提供一个可行的解决方案吗?


4
如果燃料是汽车的固有属性,且汽车销售商只销售一种类型的汽车,那么汽车销售商只销售使用一种类型燃料的汽车。要么将燃料放到销售商界面上;要么将汽车类型放到方法中。 - Andy Turner
2个回答

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,那么您可以使用返回类型协变,这是子类缩小返回类型的能力,而无需使用泛型:
interface SportsCarVendor extends CarVendor<SportsCar> {    
    @Override
    SportsCarSale sell(SportsCar car);
}

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> { }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接