"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)
如果 service
是 task
表示的类型的子类型,那么它总是可以向上转型。
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 不能组合 super
和 extends
,否则它们在其他方面可以做的事情非常有限。
我正在处理一个需要将服务添加到组件的项目。 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)
如果 service
是 task
表示的类型的子类型,那么它总是可以向上转型。
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 不能组合 super
和 extends
,否则它们在其他方面可以做的事情非常有限。