1

如果我有以下界面:

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;
    }
}

我知道Class<Collection<T>>在 Java 中无法指定文字,但为什么不能Collection.class直接转换为Class<Collection<T>>?有没有比通过投射更好的方法Object

4

3 回答 3

3

为什么不能将 Collection.class 直接转换为 Class<Collection<T>>

Collection.class有类型Class<Collection>。Java 不会编译这种类型转换,因为可以证明它不能成功。可能没有类型是Class<Collection>和的子类型Class<Collection<T>>

在泛型中,如果 A 和 B 不同并且它们是类型(不是通配符),Foo<A>则永远不是子类型,无论和Foo<B>之间的关系如何。因此, 的唯一子类型是。同样,唯一的子类型是。由于这些不相交,因此这种演员在理论上不可能成功。ABClass<Collection>SubclassOfClass<Collection>Class<Collection<T>>SubclassOfClass<Collection<T>>

有没有比通过对象投射更好的方法?

你可以通过Class<?>; 但也好不到哪里去:

return (Class<Collection<T>>) (Class<?>) Collection.class;
于 2013-07-24T01:17:06.873 回答
1

您可以将类文字传递给构造函数:

 private final Class<Collection<T>> clazz;

 public MyCollectionProcessor(Class<Collection<T>> clazz) {
      this.clazz = clazz;
 }

  public Class<Collection<T>> getElementClass() {
    return clazz;
  }

不需要演员,但需要一个额外的参数......

于 2013-07-23T09:16:44.290 回答
1

由于 Java 泛型处理,Class<List<Integer>>无法获得一个类(没有未经检查的强制转换),但将是Class<List>or 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 并且不为您提供它的实际类型实现
  • 获取原始类型为 MyElementProcessor 且实际类型参数为 TypeVariable 的 ParameterizedType
于 2013-07-23T16:55:34.777 回答