"extends" 和 "super" 的泛型通配符

Generics wildcarding with both "extends" and "super"

我正在处理一个需要将服务添加到组件的项目。 Service class 是一个没有任何方法的接口。这是我的服务如何工作的示例:

public interface Service { }

public interface CarWash extends Service {
  void washCar(Car car);
}

public interface CarRepair extends Service {
  void repairCar(Car car);
}

现在有很多这些服务的实现。一个class可以实现多个服务,如这个车库class:

public class Garage implements CarWash, CarRepair {
  @Override
  public void washCar(Car car) { /* .. */ }
  @Override
  public void repairCar(Car car) { /* .. */ }
}

向组件添加服务时,我不想在所有任务中都使用该服务,但例如仅将 Garage 用于洗车 (CarWash) 而不是修复它们 (CarRepair)。因此,我将任务指定为 classes,就像这样:

void addService(Service service, Class<? extends Service> task);

为了检查服务是否真的可以执行任务,我使用了泛型:

<T extends Service> addService(T service, Class<? super T> task);

这很好用,但不检查提供的任务是否真的是一个任务(实现 Service 的 class),所以这会起作用:

addService(myTask, Object.class);

我正在寻找一种方法来指定 service 需要实施(扩展)task 并且 task 正在扩展 Service接口,像这样(不编译)

<T extends Service> addService(T service, Class<? super T extends Service> task);

我认为 <T extends Service, S extends T> void addService(S service, Class<T> clazz) 听起来符合您的标准:

public static class Foo {                                                                                   
  public interface Service { }                                                                          

  public interface CarWash extends Service {                                                            
    void washCar();                                                                                     
  }                                                                                                     

  public interface CarRepair extends Service {                                                          
    void repairCar();                                                                                   
  }                                                                                                     

  static <T extends Service, S extends T> void addService(S service, Class<T> clazz) {}                 

  public static void main(String[] args) {                                                              
    addService(null, CarWash.class);  // Fine.                                                                  
    addService(null, Object.class);   // Compilation error.                                                          
  }
}

(我添加了一些静态变量并从方法签名中删除了 Car,因为我没有要编译的定义)

这个也可能没问题,看你怎么使用service的类型:

<T extends Service> void addService(T service, Class<T> task)

如果 servicetask 表示的类型的子类型,那么它总是可以向上转型。

addService(new Garage(), CarWash.class); // OK, Garage is a CarWash

The only problem I am having is the varargs that force all array elements to be of the same type, and therefore I cannot write addService(null, CarWash.class, CarRepair.class);

这其实是Java泛型的难题。 (C++ 可以用 variadic templates 做到这一点,这是一个 Java 不太可能得到的特性。)

因此,您可以在 Java 中解决此问题的一种方法是使用 运行 时间验证,例如:

<T extends Service> void addService(
        T service, Class<? super T> tasks...) {
    for(Class<? super T> task : tasks)
        if(!Service.class.isAssignableFrom(tasks))
            throw new IllegalArgumentException();
}

(或使用 Class<? extends Service> 并检查 task.isInstance(service)。)

但我知道我们不太喜欢那样。 ; )

Java 确实有一个叫做 intersection type 的东西(如果我们有一个类型 <? extends T & U>T & U 部分称为交集类型),但是一个交集type 不能组合 superextends,否则它们在其他方面可以做的事情非常有限。