我为维护一个Class
es和可以接受这些类的实例的处理程序而注册的库,想想Consumer<T>
。有一种设施可以为*类型及其所有子类型注册处理程序,例如
<T> void registerHandler(Class<T> type, Consumer<? super T>) { ... }
此外,有一种方法可以接收给定类型的相应处理程序:
<T> Consumer<T> getHandler(Class<? extends T> type)
现在我可以注册这样的处理程序:
Consumer<Object> printer = System.out::println;
registerHandler(Object.class, printer);
Consumer<String> screamer = s -> System.out.println(s.toUpperCase());
registerHandler(String.class, screamer);
检索处理程序也适用于子类型:
getHandler(Object.class) // => printer
getHandler(String.class) // => screamer
getHandler(Integer.class) // => printer, because Integer is a subtype of Object
我的问题是关于getHandler
方法,特别是它对通配符类型的使用。我看到了另外两种有效的使用方式:
<T> Consumer<T> getHandler(Class<? extends T> type) // option 1, from above
<T> Consumer<? super T> getHandler(Class<T> type) // option 2
<T> Consumer<? super T> getHandler(Class<? extends T> type) // option 3
// <T> Consumer<T> getHandler(Class<T> type) // non-option, does not work for subtypes.
哪种是表示类型之间这种关系的最佳方法?
我发现使用Class<? extends T>
的一个优点是可以进行以下工作:
void handle(T obj, Class<? extends T> type) {
Consumer<? super Object> handler = getHandler(type);
// or Consumer<Object>, depending on whether ? super is in the return type or not
handler.accept(obj);
}
Object o = ...;
handle(o, o.getClass());
没有? extends T
,在getHandler
中对handle
的调用将是无效的,除非它也使用Class<T>
,在这种情况下,对getClass
的调用将是无效的。