在Java中创建泛型列表数组时出错

在Java中创建泛型列表数组时出错,java,arrays,generics,syntax,Java,Arrays,Generics,Syntax,第一个代码: List<Integer>[] array = (List<Integer>[]) new Object[size]; E[] array = (E[]) new Object[size]; List<Integer>[] array = (List<Integer>[]) new List[size]; 但是我发现下面的代码是有效的 第三个代码: List<Integer>[] array = (List<

第一个代码

List<Integer>[] array = (List<Integer>[]) new Object[size]; 
E[] array = (E[]) new Object[size];
List<Integer>[] array = (List<Integer>[]) new List[size];
但是我发现下面的代码是有效的

第三个代码

List<Integer>[] array = (List<Integer>[]) new Object[size]; 
E[] array = (E[]) new Object[size];
List<Integer>[] array = (List<Integer>[]) new List[size];
List[]数组=(List[])新列表[size];
我的问题是:

  • 为什么第一个代码是错误的,而第二个代码是在有效的Java中建议的?我有什么误解吗
  • 例如:为什么下面的代码运行良好,但第一个代码是错误的

    public class Test<E>{
        E[] array;
        public Test(){
            array = (E[]) new Object[10];
        }
        public E set(E x){
            array[0] = x;
            System.out.println(array[0]);
            return array[0];
        }
    
        public static void main(String[] args){
            Test<List<Integer>> test = new Test<>();
            List<Integer> list = new ArrayList<>();
            list.add(1);
            test.set(list);
        }
    }
    
    公共类测试{
    E[]阵列;
    公开考试(){
    数组=(E[])新对象[10];
    }
    公共E集(ex){
    数组[0]=x;
    System.out.println(数组[0]);
    返回数组[0];
    }
    公共静态void main(字符串[]args){
    测试=新测试();
    列表=新的ArrayList();
    增加第(1)款;
    测试集(列表);
    }
    }
    
  • 有人能解释为什么第三个代码是正确的,但下面的代码是错误的吗
  • 第四个代码

    List<Integer>[] array = (List<Integer>[]) new Object[size]; 
    
    E[] array = (E[]) new Object[size];
    
    List<Integer>[] array = (List<Integer>[]) new List[size];
    

    List[]数组=新列表[大小]

    第一个代码

    Java中的泛型有点奇怪。出于各种原因,例如向后兼容性,泛型基本上被编译器删除,并且(大多数情况下)不会出现在已编译的代码()中。相反,它将使用()来确定应该在代码中使用什么类型。对于一个基本的未绑定泛型;此类型将是
    对象
    。因此,假设
    E
    上没有绑定,编译器将第二个代码更改为:

     Object[] array = (Object[]) new Object[size];
    
    因此,由于两个数组在擦除后具有完全相同的类型,因此在运行时没有问题,并且强制转换基本上是冗余的

    值得注意的是,只有
    E
    是无界的,这一点才有效。例如,在运行时使用
    ClassCastException

    public static <E extends Number> void genericMethod() {
        final int size = 5;
        E[] e = (E[]) new Object[size];
    }
    
    在处理代码时,记住擦除是很重要的。否则,您可能会遇到代码行为与预期不同的情况。例如,以下代码:

    这没有问题,因为
    ArrayList
    List
    的子类型

    第四个代码

    List[]array=newarrayList[size];
    
    以上内容将无法编译。以下情况明确禁止使用具有泛型类型参数的类型创建数组:

    如果正在初始化的数组的组件类型不可重新定义,则为编译时错误(§4.7)

    具有非无界通配符(
    )的泛型参数的类型不满足以下条件:

    当且仅当下列条件之一成立时,类型才可重新定义:

    • 它引用非泛型类或接口类型声明
    • 它是一种参数化类型,其中所有类型参数都是无界通配符(§4.5.1)
    • 这是一种原始类型(§4.8)
    • 它是一种基本类型(§4.2)
    • 它是一种数组类型(§10.1),其元素类型是可重新定义的
    • 它是一个嵌套类型,其中,对于每个由“.”分隔的类型T,T本身是可重新定义的

    虽然我没有时间深入研究
    JLS
    ,但我可以暗示您需要进一步研究(尽管每次我这样做,都不是一次非常愉快的旅行)

    这些不是可证明的不同类型;编译器无法判断这是否必须失败。这里还有一点,编译器不会以任何形式或形状强制转换为泛型类型,您可以轻松地执行类似的操作(仍然可以编译):

    第二点是类型擦除(同样
    JLS
    has)


    编译代码后,
    E[]
    在运行时是
    Object[]
    (除非有一个边界,但这里不是这种情况),很明显,您可以将任何您想要的东西放入其中。

    Java中数组和泛型之间的交互是混乱的,因为它们是基于不同的假设构建的。Java数组有运行时类型检查,泛型只有编译时类型检查

    Java通过结合编译时和运行时检查来实现类型安全。强制转换绕过了大多数编译时检查,但仍有运行时检查。数组的类型兼容性规则与其包含的元素类型基本相同。因此:

    Object[] a = new String[size]; //ok, but be aware of the potential for an ArrayStoreException
    String[] a = new Object[size]; //compile error
    String[] a = (String[]) new Object[size]; //runtime error
    
    当Sun决定向Java添加泛型时,他们决定使用泛型的代码应该在现有JVM上工作,因此他们决定通过擦除实现泛型。泛型类型仅在编译时存在,在运行时它们被普通类型替换

    所以在擦除之前,我们有以下陈述

    List<Integer>[] array = (List<Integer>[]) new Object[size];
    E[] array = (E[]) new Object[size];
    List<Integer>[] array = (List<Integer>[]) new List[size];
    

    E[]数组=(E[])新对象[size]结构,这违反了Java的正常类型模型,如果数组返回到非泛型上下文,将导致混乱的ClassCastException。不幸的是,通常没有更好的选择,因为类型擦除,泛型类型无法找到它的元素类型并构造正确类型的数组。

    请包含编译器错误。此外,混合泛型和数组几乎总是一件麻烦事,因为数组是协变的并保留,而泛型是不变的并被删除。在向下转换时,你必须非常小心。不是每个对象都是一个列表,但每个列表都是一个对象。检查一下,@farhanfarooki我已经更新了我的问题。如何解释我的问题1?
    List[]数组=(List[])新列表[size]这样行吗?你确定?这甚至不可能compile@Eugene我说第一个代码错了,但第二个代码正确。您可以将问题1下面的代码粘贴到ide中。它工作得很好。+1因为您提到了类型擦除+有界类型擦除。虽然演员阵容失败与否的原因仍在JLS中,但名称不同。。。
    
    List<Integer>[] array = (List<Integer>[]) new Object[size]; 
    
    array = (E[]) new Object[10];
    
    String s[][][] = new String[1][2][3];
    array = (E[]) s; // this will compile, but makes little sense 
    
    Object[] a = new String[size]; //ok, but be aware of the potential for an ArrayStoreException
    String[] a = new Object[size]; //compile error
    String[] a = (String[]) new Object[size]; //runtime error
    
    List<Integer>[] array = (List<Integer>[]) new Object[size];
    E[] array = (E[]) new Object[size];
    List<Integer>[] array = (List<Integer>[]) new List[size];
    
    List[] array = (List[]) new Object[size]; //run time error.
    Object[] array = (Object[]) new Object[size]; //no error.
    List[] array = (List[]) new List[size]; //no error.