尽管Java的类型擦除,但获得T.class

时间:2010-02-09 00:47:02

标签: java generics type-erasure

我正在尝试将接口绑定到其实现,从配置文件中读取,以便我可以将其提供给我的IoC容器。这大致是我要做的事情:

public class PropertyImplementationBinder<T> {
    // ...
    public Class getInterfaceClass() {
        return T.class; // OR Class<T>, note T is not newable
    }
    public Class getImplementationClass() {
        return /* read config file to get implementation class */;
    }
}

以某种方式可以获得T.class吗?

5 个答案:

答案 0 :(得分:30)

您需要将类显式传递给构造函数(并自行存储)。

private final Class<T> clazz;

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

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

答案 1 :(得分:9)

您可以获取类的通用超类的实际类型参数。这个blog post探讨了这个可能性,包括一个使用琐碎的匿名内部类的好小技巧。直接引用:

  

事实证明,虽然JVM不会跟踪泛型类实例的实际类型参数,但它会跟踪泛型类的子类的实际类型参数。换句话说,虽然new ArrayList<String>()在运行时实际上只是new ArrayList(),但如果类扩展ArrayList<String>,则JVM知道String是{的实际类型参数{1}}的类型参数。

答案 2 :(得分:5)

与广泛接受的内容相反,可以避免很少知道的类型擦除,这意味着被叫方确实能够知道在呼叫期间使用了哪些通用参数。

请看看: Using TypeTokens to retrieve generic parameters

文章还讨论了我们的用户使用该技术的经验。简而言之,我们最终又回到了......

传统且广泛使用的技术:“在构造函数中传递类类型”

答案 3 :(得分:1)

顺便说一下。来自@Richard Gomes的文章中的示例静态方法getType有两个错误。它应该是这样的:

static public Class<?> getType(final Class<?> klass, final int pos) {
    // obtain anonymous, if any, class for 'this' instance
    final Type superclass = klass.getGenericSuperclass();

    // test if an anonymous class was employed during the call
    if ( !(superclass instanceof ParameterizedType) ) {
            throw new RuntimeException("This instance should belong to an anonymous class");
    }

    // obtain RTTI of all generic parameters
    final Type[] types = ((ParameterizedType) superclass).getActualTypeArguments();

    // test if enough generic parameters were passed
    if ( pos >= types.length ) {
            throw new RuntimeException(String.format("Could not find generic parameter #%d because only %d parameters were passed", pos, types.length));
    }

    if (!(types[pos] instanceof Class<?>)) {
            throw new RuntimeException("Generic type is not a class but declaration definition(all you get is \"[T]\") " + types[pos]);
    }
    // return the type descriptor of the requested generic parameter
    return (Class<?>) types[pos];
}

不幸的是,它仍然不是神奇的子弹,因为如果您明确地使用代码

它会起作用
getType(new SomeObject<String>(){}.class, 0) // you get String.class

但如果你在

之类的地方打电话
getType(new SomeObject<T>(){}.class, 0) // you get T as TypeVariable<D> and not actuall class of it

只需命名T.

答案 4 :(得分:-1)

不,这是不可能的。

Java类型擦除的唯一例外是通过反射,您可以通过类的字段上的反射找出参数化类型。