简体   繁体   English

尝试获取泛型类时ClassCastException

[英]ClassCastException when trying to get the generic type class

I tried to employ the code given in this answer . 我试着使用这个答案中给出的代码。 I did this: 我这样做了:

public class ListClass<T> {
  private class ObjectFactory<T> {
    //This should the the class of generic type T which is what I need
    public final Class<T> cls;
    @SuppressWarnings ("unchecked")
    public ObjectFactory()
    {
      //This three lines are from the linked answer - I don't really understand them
      Type type = getClass().getGenericSuperclass();
      ParameterizedType paramType = (ParameterizedType) type; //java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
      cls = (Class<T>) paramType.getActualTypeArguments()[0]; 
    }
    public T createNew(... some parameters ...) {
      return (T)new Expression(cls, "new", new Object[]{... some parameters ...}).getValue();
    }
  }
  public final ObjectFactory<T> factory = new ObjectFactory<T>();

  public generateItem() {
    //let add() be method that adds item of type T to this list
    this.add(factory.createNew(... some parameters ...));
  }
}

What am I dong wrong? 我错了什么?

This technique only works if the class is parameterized with a concrete argument like this: 只有在使用如下具体参数对参数化类时,此方法才有效:

class Sub extends Super<String> {}

And then by extension: 然后通过扩展:

new Super<String>() {}

But not this way: 但不是这样的:

class Sub<T> extends Super<T> {}

And not this way: 而不是这样:

<T> Super<T> m() {
    return new Super<T>() {};
}

The ability to use getActualTypeArguments is a property of the class, not an instance, so the class needs actual type arguments to use it. 使用getActualTypeArguments的能力是类的属性,而不是实例,因此该类需要实际的类型参数才能使用它。


Per your edit, what I'd recommend doing is creating a helper routine for this: 根据您的编辑,我建议您做的是为此创建一个帮助程序:

static <T> Class<T> getActualTypeArgument(Class<?> clazz, int i) {
    Type superclazz = getClass().getGenericSuperclass();
    ParameterizedType paramType = (ParameterizedType) superclazz;

    @SuppressWarnings("unchecked")
    final Class<T> actual =
        (Class<T>) paramType.getActualTypeArguments()[i];
    return actual;
}

Then use this on the ListClass : 然后在ListClass上使用它:

class ListClass<T> {
    private ObjectFactory<T> factory = new ObjectFactory<T>(
        getActualTypeArgument(this.getClass(), 0));
}

And create the ListClass in eg the following manner: 并以下列方式创建ListClass

ListClass<GameObject> list =
    new ListClass<GameObject>() {};

Consider also just passing the Class<T> in: 还要考虑只传递Class<T>

class ListClass<T> {
    private ObjectFactory<T> factory;

    ListClass<T>(Class<T> type) {
        factory = new ObjectFactory(type);
    }

    static <T> ListClass<T> of(Class<T> type) {
        return new ListClass<T>(type);
    }
}

ListClass<GameObject> list =
    ListClass.of(GameObject.class);

Quoting the docs on Class#getGenericSuperClass() : Class#getGenericSuperClass()上引用文档:

Answers the Type for the Class which represents the receiver's superclass. 回答表示接收者超类的类的类型。 For classes which represent base types, interfaces, and for java.lang.Object the method answers null. 对于表示基类型,接口和java.lang.Object的类,该方法应答null。

Invoking it on your ObjectFactory<T> class will return the Object type, which is not a ParameterizedType . ObjectFactory<T>类上调用它将返回Object类型,该类型不是ParameterizedType

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM