尽管Java';s型擦除

尽管Java';s型擦除,java,generics,type-erasure,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

我试图将接口绑定到它的实现,就像从配置文件读取一样,这样我就可以将它提供给我的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 */;
    }
}
公共类属性实现绑定器{
// ...
公共类getInterfaceClass(){
返回T.class;//或类,注意T不可更新
}
公共类getImplementationClass(){
返回/*读取配置文件以获取实现类*/;
}
}
是否有可能获得
T.class

不,这是不可能的


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

您需要显式地将类传递到构造函数中(并自己存储)

私人期末课堂;
PropertyImplementationBinder(类别clazz){
this.clazz=clazz;
}
公共类getInterfaceClass(){
回击声;
}

您可以获取类的泛型超类的实际类型参数。这将探索由此带来的可能性,包括使用普通匿名内部类的一个很好的小技巧。直接引用:

结果表明,尽管JVM不会跟踪泛型类实例的实际类型参数,但它确实会跟踪泛型类子类的实际类型参数。换句话说,
new ArrayList()
在运行时实际上只是一个
new ArrayList()
,如果一个类扩展了
ArrayList
,那么JVM知道
String
List
的类型参数的实际类型参数


与被广泛接受和鲜为人知的情况相反,可以避免类型擦除,这意味着被调用方确实能够知道调用期间使用了哪些泛型参数

请看一看:

本文还讨论了用户使用该技术的体验。简言之,我们最终回到了


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

顺便说一句。@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(最终类klass,最终int-pos){
//获取“this”实例的匿名类(如果有)
最终类型超类=klass.getGenericSuperclass();
//测试调用期间是否使用了匿名类
if(!(参数化类型的超类实例)){
抛出新的RuntimeException(“此实例应属于匿名类”);
}
//获取所有通用参数的RTTI
最终类型[]类型=((ParameteredType)超类).getActualTypeArguments();
//测试是否通过了足够的通用参数
如果(位置>=types.length){
抛出新的RuntimeException(String.format(“找不到泛型参数#%d,因为只传递了%d个参数”),pos,types.length);
}
if(!(类别[pos]实例)){
抛出新的RuntimeException(“泛型类型不是类而是声明定义(您得到的只是\“[T]\”)”+类型[pos]);
}
//返回请求的泛型参数的类型描述符
退货(类)类型[pos];
}
不幸的是,它仍然不是灵丹妙药,因为如果代码中有明确的

getType(new SomeObject<String>(){}.class, 0) // you get String.class
getType(newsomeobject(){}.class,0)//您将获得String.class
但如果你打电话给这样的人

getType(new SomeObject<T>(){}.class, 0) // you get T as TypeVariable<D> and not actuall class of it
getType(newsomeobject(){}.class,0)//您将T作为TypeVariable获取,而不是它的实际类

只要说出T.

我想这对我来说应该是显而易见的。。。但事实并非如此。非常感谢。如果该语言在版本1中是为它设计的,它本可以为我们做到这一点。这是一个向后兼容的东西。在不破坏旧代码的情况下,将其栓接到Java5上所能做的只有这么多;在很多情况下,在课堂上不通过考试是可能的。好吧,这令人毛骨悚然,但令人惊讶(让这成为最后一条魅力评论)。事实上,我相信这应该是正确的答案,并说“你也可以在构造函数中通过类”@durilka:非常感谢你的反馈链接似乎被破坏了。。。我知道谷歌的GSON库使用这种方法,我想读一篇关于它是如何实现的文章works@ErinDrummond通过指向web.archive.org的链接修复了此问题。不,您还可以从Class.getGeneric*()和Method.getGeneric*()中找到参数化类型信息。可以参见上面的答案。在第二个示例中,如果
TypeVariable.getGenericDeclaration()
是一个类,那么仍然可以找到T的实际类型参数。在任何情况下(特别是如果它们是由超类定义的,有多个类型参数,等等),填充实际的类型参数都需要大量的工作,但是我已经编写了代码来完成。但是开发人员也知道,因为类有一个静态T。它在运行时不会改变。
getType(new SomeObject<T>(){}.class, 0) // you get T as TypeVariable<D> and not actuall class of it