Java错误:新的通用TreeNode数组

我有TreeNode的generics类:

public class TreeNode { public E key; public int num_of_children; public TreeNode [] children; public TreeNode(int num_of_children) { this.num_of_children = num_of_children; children = new TreeNode[num_of_children];// Why not: new TreeNode[num_of_children]? } public TreeNode clone() { TreeNode node = new TreeNode(num_of_children); return node; } } 

当我尝试这样做时: children = new TreeNode [num_of_children];

我收到错误。 但“新的TreeNode [num_of_children]”有效。 我读到了类型擦除,我不明白为什么TreeNode[]不起作用。 这是为什么? 请赐教!

Java不允许使用new TreeNode[]new TreeNode[]类的东西。 您可以做的唯一事情是new TreeNode[]new TreeNode[] (无界的通配符参数)。

这样做的原因有点复杂,但很有启发性。 Java中的数组在运行时知道它们的组件类型,每次放入内容时,它会检查它是否是组件类型的实例,如果没有,则抛出exception(这与数组类型的协变性有关,因此在编译时本质上不安全)。

 Object[] foo = new Integer[5]; foo[2] = "bar"; // compiles fine, but throws ArrayStoreException at runtime 

现在添加generics。 通用组件类型的问题在于,您无法在运行时检查对象是否是TreeNodeTreeNode的实例(而不是TreeNode ),因为generics从运行时类型中删除。 它只能检查TreeNode ,但不能检查组件类型。 但程序员可能已经预料到数组的这种检查和exception抛出行为,因为它通常有效。 因此,为了避免这种意外失败,Java不允许它。 (在大多数代码中,你不会遇到这个问题,因为你不会混合相同类型但不同类型参数的对象。但理论上可能会出现。)

当然,您可以通过创建一个raw或wildcard参数类型的数组,然后转换为正确的类型来解决问题,例如(TreeNode)new TreeNode[5] 。 有什么不同? 好吧,这是一个未经检查的演员,它会产生一个警告,而你,程序员,对所有可能在以后发生的不安全事情负责。 如果它做了意想不到的事情,编译器可以说,“我们告诉你了!”。

因为Java语言规范写道 :

数组创建表达式创建一个对象,该对象是一个新数组,其元素的类型由PrimitiveType或ClassOrInterfaceType指定。

如果ClassOrInterfaceType不表示可再现类型(第4.7节),则为编译时错误。 否则,ClassOrInterfaceType可以命名任何命名引用类型,甚至是抽象类类型(第8.1.1.1节)或接口类型(第9节)。

上述规则意味着数组创建表达式中的元素类型不能是参数化类型,而不是无界通配符。

我不清楚他们为什么要这样做。 当然,数组的组件类型必须在运行时可用,如果程序员与源代码中指定的类型不同,则会对程序员产生误导。 考虑:

 E[] a = new E[10]; 

在这里,如果编译器使用E的擦除作为数组组件类型会很糟糕,因为程序员可能很好地依赖于数组来检查除了E实例之外什么都没有存储在其中。

不太清楚允许以下内容会带来什么危害:

 List[] lists = new List[10]; 

我唯一想到的是,分配一个数组元素相当于一个未经检查的强制转换,因为该数组会检查该元素是否为List ,但不是它是List ,因此无法抛出ArrayStoreException

实际上,只要您意识到数组不会检查其组件类型的类型参数,就可以安全地抑制此警告。