我正在尝试使用泛型,主要是为了练习和我有一点想法。
目前我遇到问题: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);
答案 0 :(得分:4)
你似乎对Java中的泛型感到困惑。
Java并没有像在C#中那样实现Generics:你无法在运行时检索泛型类型的类型信息,因为它在编译后根本就没有保存(参见:{ {3}})
这意味着如果我声明一个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);
答案 1 :(得分:2)
错误的根源是示例中的this
是Foo<String>
的实例,其超类是非参数化类型java.lang.Object
。因此getGenericSuperclass()
正在为您Object.class
而不是ParameterizedType
。
您尝试使用的模式类似于type token等库使用的“gson”技巧,您可以在其中定义泛型类型的匿名子类。它是为了捕获通用超类签名中的类型参数。如果你做了
,你的代码就可以了Foo<Bar> com = new Foo<Bar>(100) {};
空括号使它成为一个匿名类,其通用超类是代表ParameterizedType
的{{1}}。
请注意,只有在使用非参数化类文字实例化type参数时,此技巧才有效。如果你有像
这样的方法Foo<Bar>
它会失败,因为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
。
答案 2 :(得分:0)
要回答您的原始问题:您正在尝试将Type
类型的对象转换为类型Class
。由于Type
是Class
的超类型,因此会导致异常 - 这是一个令人困惑的句子。
这是我的第二点:除非你真的需要,否则不使用反射。这是java的黑魔法!同样正如Snaipe指出的那样,这是最重要的事情,因为类型擦除反射不会帮助你解决与泛型相关的任何问题。
答案 3 :(得分:0)
只有在您Foo
的子类化时,您才能尝试做的事情,提供T
类型定义中捕获的Foo
的实际值:
class StringFoo extends Foo<String> {}
然后init
应该按预期工作。如果没有在类型定义中捕获T
的实际值,则无法在运行时恢复T
的值。
答案 4 :(得分:0)
这是一个解决方案
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;
}