1

I have generic class of 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;
}

}

When I try to do:children = new TreeNode<E> [num_of_children];

I get error. But "new TreeNode[num_of_children]" works. I read about type erasure, and I don't understand why TreeNode<E>[] doesn't work. Why is that? Please enlighten me!

4

2 回答 2

3

Java 不允许使用new TreeNode<String>[]和之类的东西。new TreeNode<E>[]您唯一能做的就是new TreeNode[]new TreeNode<?>[](无界通配符参数)。

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

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

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

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

于 2012-06-23T10:53:42.953 回答
1

因为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];

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

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

于 2012-06-23T08:19:20.553 回答