Java Generic Type Arguments未经过验证

时间:2015-04-02 19:09:20

标签: java generics

我只是想知道,为什么错误类型值的赋值不会导致任何运行时异常。我准备了一个小例子,其中类X包含一个实现接口A的通用变量“object”,而类Y声明这个泛型是B类型

public interface A{};
public class B implements A{}
public class C implements A{}
public class X<T extends A>{
  T object;
  void setObject(T t){
    object = t;
  }
  T getObject(){
   return object;
  }
}
public class Y extends X<B>{}

如果我有一个X hold和Y-Object类型的变量,编译器允许分配任何值,这在我看来是正确的。但是在运行时,我会期待一个例外。

public static void main(String[] args) throws Exception{
  X<A> foo = (X<A>) Class.forName("com.abc.Y").newInstance();
  foo.setObject(new B()); //should not fail
  foo.setObject(new C()); //should fail
}

在Y类尝试访问该对象之前,我没有任何异常。

如果我将此方法添加到类Y,我在setObject上得到ClassCastException,但实际上我不想用正确的Class覆盖所有方法。

public class Y extends X<B>{
  void setObject(B t){
    super.setObject(t);
  }
}

2 个答案:

答案 0 :(得分:2)

原因是因为您在运行时using Reflection生成对象,而泛型只在编译时检查。

这是因为使用type erasure实现了Java Generics。也就是说,它们在编译代码中是not present

答案 1 :(得分:1)

这种行为的原因是java的类型擦除。 类型擦除通常意味着所有泛型都被java转换所取代(这就是为什么你得到ClassCastException)。 所以这个:

List<String> list = new ArrayList<String>();
list.add("text");
String x = list.get(0);

将转换为:

List list = new ArrayList();
list.add("text");
String x = (String) list.get(0);

您可以在此处详细了解: http://en.wikipedia.org/wiki/Generics_in_Java#Problems_with_type_erasure