如何确定泛型类?

Jaa*_*ans 60 java generics

我正在创建一个泛型类,并且在其中一个方法中我需要知道当前使用的泛型类的Class.原因是我调用的方法之一将此作为参数.

例:

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

显然,上面的示例不起作用并导致以下错误:类型参数T的非法类文字.

我的问题是:有人知道一个很好的选择或解决方法吗?

Nic*_*las 49

仍然存在相同的问题:通用信息在运行时被擦除,无法恢复.解决方法是在静态方法的参数中传递类T:

public class MyGenericClass<T> {

    private final Class<T> clazz;

    public static <U> MyGenericClass<U> createMyGeneric(Class<U> clazz) {
        return new MyGenericClass<U>(clazz);
    }

    protected MyGenericClass(Class<T> clazz) {
        this.clazz = clazz;
    }

    public void doSomething() {
        T instance = clazz.newInstance();
    }
}
Run Code Online (Sandbox Code Playgroud)

这很难看,但它确实有效.


小智 22

我只是指出了这个解决方案:

import java.lang.reflect.ParameterizedType;

public abstract class A<B> {
    public Class<B> g() throws Exception {
        ParameterizedType superclass =
            (ParameterizedType) getClass().getGenericSuperclass();

        return (Class<B>) superclass.getActualTypeArguments()[0];
    }
}
Run Code Online (Sandbox Code Playgroud)

如果A由子类给出具体类型,则此方法有效:

new A<String>() {}.g() // this will work

class B extends A<String> {}
new B().g() // this will work

class C<T> extends A<T> {}
new C<String>().g() // this will NOT work
Run Code Online (Sandbox Code Playgroud)

  • 它工作得很好,但我在"(Class <T>)superclass.getActualTypeArguments()[0];"附近得到了"类型安全:从类型到类<T>>未经检查的强制转换"警告.如何删除它? (2认同)

Ste*_*ins 5

不幸的是,克里斯托夫所写的解决方案仅在非常有限的情况下有效。[编辑:如下所述,我不再记得我对这句话的推理,并且可能是错误的:“请注意,首先,这仅适用于抽象类。”]下一个困难是仅适用g()A. 不过我们可以解决这个问题:

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);
}
Run Code Online (Sandbox Code Playgroud)

这在实践中的许多情况下都有效,但并非总是有效。考虑:

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

(new Foo<String,List<Object>>() {}).g();
Run Code Online (Sandbox Code Playgroud)

这将抛出 a ClassCastException,因为这里的类型参数根本不是 aClass或 a ;ParameterizedType这是TypeVariable T. 所以现在你会陷入困境,试图弄清楚类型T应该代表什么,等等。

我认为唯一合理的、通用的答案类似于尼古拉斯的最初答案——一般来说,如果您的类需要实例化编译时未知的其他类的对象,则您的类的用户需要传递该类文字(或者,也许是一个工厂)显式地添加到您的类中,而不仅仅依赖于泛型。