![](/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.