尽管 Java 具有类型擦除功能,但仍获得 T.class
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2225979/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting T.class despite Java's type-erasure
提问by Kaleb Pederson
I'm trying to bind an interface to its implementation as read from a configuration file so that I can feed it to my IoC container. Here's roughly what I'm trying to do:
我正在尝试将接口绑定到从配置文件读取的实现,以便我可以将它提供给我的 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 */;
}
}
Is it somehow possible to get T.class
?
是否有可能获得T.class
?
采纳答案by Thilo
You need to explicitly pass the class into the constructor (and store it yourself).
您需要将类显式传递给构造函数(并自己存储)。
private final Class<T> clazz;
PropertyImplementationBinder(Class<T> clazz){
this.clazz = clazz;
}
public Class<T> getInterfaceClass() {
return clazz;
}
回答by cletus
No it's not possible.
不,这是不可能的。
The only exception to Java's type erasure is that via reflection you can find out the parameterized type via reflection on a class's fields.
Java 类型擦除的唯一例外是通过反射,您可以通过对类字段的反射找出参数化类型。
回答by kloffy
You can get the actual type arguments for a generic superclass of a class. This blog postexplores the possibilities presented by this, including a nice little trick using trivial anonymous inner classes. To quote directly:
您可以获得类的泛型超类的实际类型参数。这篇博文探讨了由此带来的可能性,包括使用琐碎的匿名内部类的一个不错的小技巧。直接引用:
It turns out that while the JVM will not track the actual type arguments for instances of a generic class, it does track the actual type arguments for subclassesof generic classes. In other words, while a
new ArrayList<String>()
is really just anew ArrayList()
at runtime, if a class extendsArrayList<String>
, then the JVM knows thatString
is the actual type argument forList
's type parameter.
事实证明,虽然 JVM 不会跟踪泛型类实例的实际类型参数,但它会跟踪泛型类的子类的实际类型参数。换句话说,虽然 a在运行时
new ArrayList<String>()
实际上只是 anew ArrayList()
,但如果一个类扩展了ArrayList<String>
,那么 JVM 就知道它String
是 的类型参数的实际List
类型参数。
回答by Richard Gomes
Contrary to what is widely accepted and rarely known type erasure can be avoided, which means that the callee do have the ability to know which generic parameters were employed during the call.
与广泛接受且鲜为人知的类型擦除相反,可以避免类型擦除,这意味着被调用者确实有能力知道在调用期间使用了哪些泛型参数。
Please have a look at: Using TypeTokens to retrieve generic parameters
请查看: 使用 TypeTokens 检索泛型参数
The article also talks about the experiences of our users with the technique. In a nutshell, we ended up falling back to the...
这篇文章还讨论了我们的用户使用该技术的经验。简而言之,我们最终回到了......
Conventional and widely used technique: "Pass class types in constructors"
常规和广泛使用的技术:“在构造函数中传递类类型”
回答by durilka
Btw. The example static method getType in article from @Richard Gomes has two errors. it should go like this:
顺便提一句。@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];
}
Unfortunately it's still not the magic bullet because it works if you have in code explicitly
不幸的是,它仍然不是灵丹妙药,因为如果您在代码中明确地使用它,它就可以工作
getType(new SomeObject<String>(){}.class, 0) // you get String.class
but if you call this on something like
但如果你把它称为类似的东西
getType(new SomeObject<T>(){}.class, 0) // you get T as TypeVariable<D> and not actuall class of it
Just name T.
就叫T。