Java:将Collection.class转换为Class <collection <t>&gt; </collection <t>

时间:2013-07-23 09:10:33

标签: java generics casting

如果我有以下界面:

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投射更好的方式?

3 个答案:

答案 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 ...
    };
}

在这种情况下,您将:

  • 没有获取ParameterizedType,而是直接获取MyElementProcessor.class,其类型参数是TypeVariable,并没有为您提供实际的类型实现
  • 获取ParameterizedType,其原始类型为MyElementProcessor,实际类型参数为TypeVariable