Java 未验证通用类型参数

Java Generic Type Arguments not validated

我只是想知道,为什么分配错误的类型值不会导致任何运行时异常。我准备了一个小例子,其中 class X 持有一个实现接口 A 的泛型变量 "object" 并且 class 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 类型的变量和 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
}

我没有得到任何异常,直到 class Y,尝试访问该对象。

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

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

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

这是由于 Java 在编译代码中使用 type erasure. That is, they're not present 实现泛型。

该行为的原因是 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