[英]ClassCastException:java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
I'm trying to work with generics mostly for practice and for a little idea I had. 我正在尝试使用泛型,主要是为了练习和我有一点想法。 At the moment I have a problem with:
ClassCastException:java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
. 目前我遇到了一个问题:
ClassCastException:java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
。 Most of the topics I found about this where from users that posted very specific code. 我发现的大多数主题来自发布非常具体代码的用户。 This makes it really harder for me to understand.
这让我很难理解。 I tried to make the problem as simple as possible but still related to my actual problem.
我试图让问题变得尽可能简单,但仍然与我的实际问题有关。 I hope someone can help.
我希望有人能帮帮忙。
The Bar class: 酒吧班:
class Bar { }
The Foo class: Foo类:
class Foo<T> {
ArrayList<Object> list;
Foo(int initialCapacity) {
init(initialCapacity);
}
void init(int initialCapacity) {
list = new ArrayList<Object>(initialCapacity);
for (int i = 0; i < initialCapacity; i++) {
try {
list.add(((Class)((ParameterizedType)this.getClass().
getGenericSuperclass()).getActualTypeArguments()[0]).newInstance());
}
catch (InstantiationException e) {
}
catch (IllegalAccessException e) {
}
}
}
}
use: 使用:
Foo<Bar> com = new Foo<Bar>(100);
You seem to be confused about Generics in Java. 你似乎对Java中的泛型感到困惑。
Java does not implement Generics the same way it is done in, say, C# : you cannot retrieve type information of a generic type at runtime, because it's simply not saved after compilation (see: type erasure ) Java没有像在C#中那样实现Generics:你不能在运行时检索泛型类型的类型信息,因为它在编译后根本就没有保存(参见: type erasure )
This means that if I declare a variable of type List<MyObject>
, then I cannot know if it is a list of MyObject, because the type information is lost, and the class of this list is just List, which is not implementing ParameterizedType. 这意味着如果我声明一个
List<MyObject>
类型的变量,那么我不知道它是否是MyObject的列表,因为类型信息丢失了,这个列表的类只是List,它没有实现ParameterizedType。
The only time where the generic type information is saved, is when it is known at compile time for a type definition: 保存泛型类型信息的唯一时间是在编译时知道类型定义:
public class MyList extends List<MyObject> {}
Here, MyList.class.getGenericSuperclass()
should be implementing ParameterizedType. 这里,
MyList.class.getGenericSuperclass()
应该实现ParameterizedType。 I'm afraid that what you are trying to do here is not possible, or at least, it could be working, if init was called on a class inheriting Foo, such as : 我担心你在这里尝试做的事情是不可能的,或者至少,它可能有效,如果在继承Foo的类上调用init,例如:
public class StringFoo extends Foo<String> {
public StringFoo(int initialCapacity) {
super(initialCapacity);
}
}
StringFoo foo = new StringFoo(100);
The root of the error is that this
in your example is an instance of Foo<String>
, whose superclass is the non-parameterized type java.lang.Object
. 错误的根源在于您的示例中的
this
是Foo<String>
的实例,其超类是非参数化类型java.lang.Object
。 Thus getGenericSuperclass()
is giving you Object.class
instead of a ParameterizedType
. 因此
getGenericSuperclass()
为您提供Object.class
而不是ParameterizedType
。
The pattern you're trying to use looks like the " type token " trick used by libraries such as gson where you define an anonymous subclass of the generic type at the point where you want to use it in order to capture the type parameters in the generic superclass signature. 您尝试使用的模式看起来像库这样的“ 类型令牌 ”技巧,例如gson ,您可以在要使用它的位置定义泛型类型的匿名子类,以便捕获类型参数。通用超类签名。 Your code would work if you did
如果你这样做,你的代码就可以了
Foo<Bar> com = new Foo<Bar>(100) {};
The empty braces make this an anonymous class whose generic superclass is the ParameterizedType
representing Foo<Bar>
. 空括号使它成为一个匿名类,其通用超类是表示
Foo<Bar>
的ParameterizedType
。
Note that this trick can only work when you instantiate the type parameter with a non-parameterized class literal. 请注意,只有在使用非参数化类文字实例化type参数时,此技巧才有效。 If you had a method like
如果你有像这样的方法
static <E> Foo<E> makeFoo(E element) {
Foo<E> f = new Foo<E>(100) {};
// do something with element
}
it would fail because ((ParameterizedType)this.getClass().getGenericSuperclass()) .getActualTypeArguments()[0]
would be a TypeVariable
rather than a Class
. 它会失败,因为
((ParameterizedType)this.getClass().getGenericSuperclass()) .getActualTypeArguments()[0]
将是TypeVariable
而不是Class
。 Similarly 同样
Foo<List<String>> listFoo = new Foo<List<String>>(5){}
would fail because here the first actual type argument is a ParameterizedType
rather than a Class
. 会失败,因为这里第一个实际的类型参数是
ParameterizedType
而不是Class
。
To answer your original question: you are trying to cast an object of the type Type
to the type Class
. 要回答您的原始问题:您正在尝试将
Type
的对象Type
转换为类Class
。 Since Type
is a supertype of Class
this results in an exception - what a confusing sentence. 由于
Type
是Class
的超类型,因此会导致异常 - 这是一个令人困惑的句子。
And here comes my second point: Do not use reflection unless you really really have to. 而这才是我的第二点: 不要使用反射,除非你真的不得不这样做。 It's the black magic of java!
这是java的黑魔法! Also as Snaipe points out, and this is the most important thing, due to type erasure reflection will not help you with any problem related to generics.
同样正如Snaipe指出的那样,这是最重要的事情,由于类型擦除反射不会帮助您解决与泛型相关的任何问题。
What you're trying to do is only possible if you subclass Foo
, providing an actual value for T
that is captured in Foo
's type definition: 你想要做的只有在你为
Foo
子类化时才有可能,提供在Foo
类型定义中捕获的T
的实际值:
class StringFoo extends Foo<String> {}
Then init
should work as you expect. 然后
init
应该按预期工作。 Without capturing an actual value for T
in a type definition, there's no way to recover the value of T
at runtime. 如果没有在类型定义中捕获
T
的实际值,则无法在运行时恢复T
的值。
This is a solution 这是一个解决方案
public TO getTo() throws Exception{
if (to == null) {
try{
to = ((Class<TO>)((ParameterizedType)this.getClass().
getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
}catch(ClassCastException cce){
cce.printStackTrace();
to = ((Class<TO>)((ParameterizedType)(((Class<TO>)
this.getClass().getAnnotatedSuperclass().getType()).getGenericSuperclass()))
.getActualTypeArguments()[0]).newInstance();
}
}
return to;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.