如果我有以下界面:
interface MyElementProcessor<T> {
void doSomethingWith(T element);
Class<T> getElementClass();
/* more functions... */
}
假设我想为Collection<T>
这样的泛型类型实现此功能。我如何实施getElementClass()
?到目前为止,我最好的尝试是这样的:
class MyCollectionProcessor<T> implements MyElementProcessor<Collection<T>> {
public void doSomethingWith(Collection<T> element) { /* ... */ }
public Class<Collection<T>> getElementClass() {
// Ugly, but the only way I have found to cast to Class<Collection<T>>:
return (Class<Collection<T>>) (Object) Collection.class;
}
}
我知道在Java中无法指定Class<Collection<T>>
字面值,但为什么不能将Collection.class
直接转换为Class<Collection<T>>
?有没有比通过Object
投射更好的方式?
答案 0 :(得分:3)
为什么不能直接将Collection.class强制转换为
Class<Collection<T>>
?
Collection.class
的类型为Class<Collection>
。 Java不会编译此类型转换,因为可以证明它不能成功。可能没有类型是Class<Collection>
和Class<Collection<T>>
的子类型。
在泛型中,如果A和B不同且Foo<A>
不是Foo<B>
和{{1 }}。因此,A
的唯一子类型为B
。同样,Class<Collection>
的唯一子类型是SubclassOfClass<Collection>
。由于这些不相交,所以这种演员阵容理论上无法成功。
有没有比通过Object转换更好的方法?
你可以通过Class<Collection<T>>
投射;但它并没有好多少:
SubclassOfClass<Collection<T>>
答案 1 :(得分:1)
您可以将类文字传递给构造函数:
private final Class<Collection<T>> clazz;
public MyCollectionProcessor(Class<Collection<T>> clazz) {
this.clazz = clazz;
}
public Class<Collection<T>> getElementClass() {
return clazz;
}
不需要演员而是额外的参数...
答案 2 :(得分:1)
由于Java泛型处理,无法获取Class<List<Integer>>
类(未经过未经检查的强制转换),但是Class<List>
或Class<List<?>>
。
因此,如果您在ElementProcessor
中使用参数化类型,我建议您将方法更改为Class<? super T> getElementClass()
两个例子:
interface MyElementProcessor<T> {
void doSomethingWith(T element);
Class<? super T> getElementClass();
/* more functions... */
}
SimpleElementProcessor implements MyElementProcessor<Integer> {
public void doSomethingWith(Collection<Integer> element) { /* ... */ }
public Class<Integer> getElementsClass() {
return Integer.class;
}
}
CollectionElementProcessor<E> implements MyElementProcessor<Collection<E>> {
public void doSomethingWith(Collection<Collection<E>> element) { /* ... */ }
// This works because Class<Collection<?>> is a valid substitute for Class<? super T>
public Class<Collection<?>> getElementsClass() {
return (Class<Collection<?>>) Collection.class; // Maybe the cast isn't needed
}
}
至于获取元素类,您可以使用反射:如果您的类型派生 MyElementProcessor,您可以像这样获取它:
for(Type interface : getClass().getGenericInterfaces()) {
if(interface instanceof ParameterizedType && ((ParameterizedType) interface).getRawType == MyElementProcessor.class)
Type myElementsType = ((ParameterizedType) interface).getActualTypeArguments()[0];
这仅适用于派生类,即匿名类或声明类型,如果你因为类型擦除而使用它,它将无法工作(这个例子是虚拟的:它只是一个例子):
public <T> MyElementProcessor newInstance() {
return new MyElementProcessor<T> {
// overridden methods ...
};
}
在这种情况下,您将: