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

Whi*_*cal 1 java generics types casting exception

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

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

    import Test.*; //Inner classes
    import java.util.List;
    import java.util.ArrayList;
    
    public class Test<E extends Object> {
    
        private List<E> list = new ArrayList<E>();
        public Test() {}
    
        public static void main(String[] args) {
            Test<String> a = new Test<String>();
            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); }
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

Hov*_*els 5

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

public void addElement(E node) {
  list.add(node);
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • @ user1352530:在运行时,由于泛型类型擦除,List只是一个Object列表,因此第一次转换甚至不会发生.但是当您从列表中提取项目后,场景演员*会*发生并导致您的异常. (2认同)
  • @ user1352530:最好将泛型视为编译时_annotations._它们在运行时实际上没有被检查过. (2认同)