Java错误:新的通用TreeNode数组

Java错误:新的通用TreeNode数组,java,arrays,generics,initialization,treenode,Java,Arrays,Generics,Initialization,Treenode,我有TreeNode的通用类: public class TreeNode<E> { public E key; public int num_of_children; public TreeNode<E> [] children; public TreeNode(int num_of_children) { this.num_of_children = num_of_children; children = new TreeNode[num_of_c

我有TreeNode的通用类:

public class TreeNode<E> {
public E key;
public int num_of_children;
public TreeNode<E> [] children;


public TreeNode(int num_of_children)
{
    this.num_of_children = num_of_children;
    children = new TreeNode[num_of_children];// Why not: new TreeNode<E>[num_of_children]?
}

public TreeNode<E> clone()
{
    TreeNode<E> node = new TreeNode<E>(num_of_children);
    return node;
}

}
公共类树节点{
公钥;
儿童的公共整数;
公共TreeNode[]儿童;
公共树节点(子节点的整数)
{
this.num_of_children=num_of_children;
children=new TreeNode[num_of_children];//为什么不:new TreeNode[num_of_children]?
}
公共树节点克隆()
{
TreeNode=新的TreeNode(子节点的数量);
返回节点;
}
}
当我尝试这样做时:
children=newtreenode[num_of_children];

我犯了一个错误。但是“新树节点[儿童数量]”是有效的。 我读过关于类型擦除的文章,不明白为什么
TreeNode[]
不起作用。
为什么呢?请开导我

因为Java语言规范:

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

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

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

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

E[] a = new E[10];
在这里,如果编译器使用擦除
E
作为数组组件类型,这将是不好的,因为程序员很可能依赖数组来检查数组中是否只存储了
E
的实例

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

List<E>[] lists = new List<E>[10];
List[]lists=新列表[10];
我想到的唯一一件事是,分配数组元素相当于未经检查的强制转换,因为数组会检查元素是否是
列表
,但不会检查它是否是
列表
,因此无法抛出
ArrayStoreException


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

Java不允许使用
new TreeNode[]
new TreeNode[]
等操作。您只能执行
newtreenode[]
newtreenode[]
(无界通配符参数)

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

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

当然,您可以通过创建原始或通配符参数类型的数组,然后强制转换为适当的类型,例如
(TreeNode)new TreeNode[5]
,来解决此问题。有什么区别?好吧,这是一个未经检查的强制转换,它会生成一个警告,而你,程序员,对以后可能发生的所有不安全的事情负责。如果出现意外情况,编译器会说,“我们早就告诉过你了!”

泛型和数组在一起真的不能很好地发挥作用。避免对数组使用泛型。
Object[] foo = new Integer[5];
foo[2] = "bar"; // compiles fine, but throws ArrayStoreException at runtime