为什么List 在编译和执行时吸收not-type元素?

我有这个演示,我不需要一个具有重绘架构的特定解决方案,但只是理解为什么这样做以及我为避免它而遗漏的任何事情。 我想知道为什么:

  • 编译器允许将不是列表类型的元素插入到列表中
  • 当我们尝试获取元素而不是在推送元素时抛出ClassCastexception

    import Test.*; //Inner classes import java.util.List; import java.util.ArrayList; public class Test { private List list = new ArrayList(); public Test() {} public static void main(String[] args) { Test a = new Test(); a.addElement(new String()); a.addElement(new Integer(0)); // No complain in comp/run-time, I dont understand why CastException is not thrown here String class1 = a.getElement(0); String class2 = a.getElement(1); //No complain in comp but ClassCastException: Integer cannot be cast to String //Integer class3 = a.getElement(1); //Compilation error } public void addElement (Object node) { list.add((E) node); } //No complain in comp/run-time public E getElement(int index) { return list.get(index); } } 

什么可以解决方案? 注意我需要传递SuperClass而不是类型E的addElement行。这是我的架构所需要的,这只是一个简单的模拟演示。 但无论如何,类型E的转换应该按照需要运行并在运行时抛出CastExeption,不应该吗?

问题是(E) node由于类型擦除而不进行运行时类型检查。 编译后,有关generics类型的所有信息都将丢失。

Java编译器应该警告你:

 Type safety: Unchecked cast from Object to E 

您可以通过使用java.lang.Class的引用手动执行此检查:

 private Class clazz; public Test(Class clazz) { this.clazz = clazz; } public void addElement (Object node) { list.add(clazz.cast(node)); } public static void main(String[] args) { Test test = new Test(String.class); test.addElement("test"); test.addElement(Integer.intValue(10)); } 

您的addElement方法没有正确使用generics来允许编译时错误捕获。 它应该是:

 public void addElement(E node) { list.add(node); } 

一旦使用Object强制转换并将其强制转换为E,就会失去编译时类型检查的好处。 这就是为什么我们首先使用generics,以避免使用Object变量并避免强制转换。

请注意,在运行时,由于generics类型擦除,List只是一个对象列表,因此当您将对象放入列表时,第一次转换甚至不会发生。 但是当你从列表中提取项目并需要将它分配给具体的类型变量时,会发生场景转换,这会导致抛出exception。