How to determine the class of a generic type?

2018-12-31 22:47发布

I'm creating a generic class and in one of the methods I need to know the Class of the generic type currently in use. The reason is that one of the method's I call expects this as an argument.

Example:

public class MyGenericClass<T> {
  public void doSomething() {
    // Snip...
    // Call to a 3rd party lib
    T bean = (T)someObject.create(T.class);
    // Snip...
  }
}

Clearly the example above doesn't work and results in the following error: Illegal class literal for the type parameter T.

My question is: does someone know a good alternative or workaround for this?

标签: java generics
7条回答
荒废的爱情
2楼-- · 2018-12-31 23:15

Unfortunately Christoph's solution as written only works in very limited circumstances. [EDIT: as commented below I no longer remember my reasoning for this sentence and it is likely wrong: "Note that this will only work in abstract classes, first of all."] The next difficulty is that g() only works from DIRECT subclasses of A. We can fix that, though:

private Class<?> extractClassFromType(Type t) throws ClassCastException {
    if (t instanceof Class<?>) {
        return (Class<?>)t;
    }
    return (Class<?>)((ParameterizedType)t).getRawType();
}

public Class<B> g() throws ClassCastException {
    Class<?> superClass = getClass(); // initial value
    Type superType;
    do {
        superType = superClass.getGenericSuperclass();
        superClass = extractClassFromType(superType);
    } while (! (superClass.equals(A.class)));

    Type actualArg = ((ParameterizedType)superType).getActualTypeArguments()[0];
    return (Class<B>)extractClassFromType(actualArg);
}

This will work in many situations in practice, but not ALL the time. Consider:

public class Foo<U,T extends Collection<?>> extends A<T> {}

(new Foo<String,List<Object>>() {}).g();

This will throw a ClassCastException, because the type argument here isn't a Class or a ParameterizedType at all; it's the TypeVariable T. So now you would be stuck trying to figure out what type T was supposed to stand for, and so on down the rabbit hole.

I think the only reasonable, general answer is something akin to Nicolas's initial answer -- in general, if your class needs to instantiate objects of some other class that is unknown at compile-time, users of your class need to pass that class literal (or, perhaps, a Factory) to your class explicitly and not rely solely on generics.

查看更多
登录 后发表回答