![](/img/trans.png)
[英]java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
[英]ClassCastException:java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
我正在尝试使用泛型,主要是为了练习和我有一点想法。 目前我遇到了一个问题: ClassCastException:java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
。 我发现的大多数主题来自发布非常具体代码的用户。 这让我很难理解。 我试图让问题变得尽可能简单,但仍然与我的实际问题有关。 我希望有人能帮帮忙。
酒吧班:
class Bar { }
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) {
}
}
}
}
使用:
Foo<Bar> com = new Foo<Bar>(100);
你似乎对Java中的泛型感到困惑。
Java没有像在C#中那样实现Generics:你不能在运行时检索泛型类型的类型信息,因为它在编译后根本就没有保存(参见: type erasure )
这意味着如果我声明一个List<MyObject>
类型的变量,那么我不知道它是否是MyObject的列表,因为类型信息丢失了,这个列表的类只是List,它没有实现ParameterizedType。
保存泛型类型信息的唯一时间是在编译时知道类型定义:
public class MyList extends List<MyObject> {}
这里, MyList.class.getGenericSuperclass()
应该实现ParameterizedType。 我担心你在这里尝试做的事情是不可能的,或者至少,它可能有效,如果在继承Foo的类上调用init,例如:
public class StringFoo extends Foo<String> {
public StringFoo(int initialCapacity) {
super(initialCapacity);
}
}
StringFoo foo = new StringFoo(100);
错误的根源在于您的示例中的this
是Foo<String>
的实例,其超类是非参数化类型java.lang.Object
。 因此getGenericSuperclass()
为您提供Object.class
而不是ParameterizedType
。
您尝试使用的模式看起来像库这样的“ 类型令牌 ”技巧,例如gson ,您可以在要使用它的位置定义泛型类型的匿名子类,以便捕获类型参数。通用超类签名。 如果你这样做,你的代码就可以了
Foo<Bar> com = new Foo<Bar>(100) {};
空括号使它成为一个匿名类,其通用超类是表示Foo<Bar>
的ParameterizedType
。
请注意,只有在使用非参数化类文字实例化type参数时,此技巧才有效。 如果你有像这样的方法
static <E> Foo<E> makeFoo(E element) {
Foo<E> f = new Foo<E>(100) {};
// do something with element
}
它会失败,因为((ParameterizedType)this.getClass().getGenericSuperclass()) .getActualTypeArguments()[0]
将是TypeVariable
而不是Class
。 同样
Foo<List<String>> listFoo = new Foo<List<String>>(5){}
会失败,因为这里第一个实际的类型参数是ParameterizedType
而不是Class
。
要回答您的原始问题:您正在尝试将Type
的对象Type
转换为类Class
。 由于Type
是Class
的超类型,因此会导致异常 - 这是一个令人困惑的句子。
而这才是我的第二点: 不要使用反射,除非你真的不得不这样做。 这是java的黑魔法! 同样正如Snaipe指出的那样,这是最重要的事情,由于类型擦除反射不会帮助您解决与泛型相关的任何问题。
你想要做的只有在你为Foo
子类化时才有可能,提供在Foo
类型定义中捕获的T
的实际值:
class StringFoo extends Foo<String> {}
然后init
应该按预期工作。 如果没有在类型定义中捕获T
的实际值,则无法在运行时恢复T
的值。
这是一个解决方案
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.