繁体   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