簡體   English   中英

ClassCastException:java.lang.Class無法強制轉換為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);

錯誤的根源在於您的示例中的thisFoo<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 由於TypeClass的超類型,因此會導致異常 - 這是一個令人困惑的句子。

而這才是我的第二點: 不要使用反射,除非你真的不得不這樣做。 這是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM