2012-06-23 2 views
1

У меня есть общий класс TreeNode:Java Ошибка: Новые родовые 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; 
} 

} 

Когда я пытаюсь сделать: children = new TreeNode<E> [num_of_children];

я получаю сообщение об ошибке. Но «новый TreeNode [num_of_children]» работает. Я читал о стирании типа, и я не понимаю, почему TreeNode<E>[] не работает. Почему? Пожалуйста, просветите меня!

+0

Дженерики и массивы _really не играют хорошо вместе. Избегайте использования дженериков с массивами. –

ответ

2

Такие вещи, как new TreeNode<String>[] и new TreeNode<E>[], запрещены Java. Единственное, что вы можете сделать, это new TreeNode[] и new TreeNode<?>[] (неограниченный параметр подстановки).

Причина этого немного сложная, но поучительная. Массивы на Java знают свой тип компонента во время выполнения, и каждый раз, когда вы что-то вставляете, он проверяет, является ли это экземпляром типа компонента, а если нет, генерирует исключение (это связано с тем, что типы массивов ковариантны и поэтому по своей сути небезопасно во время компиляции).

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

Теперь добавьте дженерики. Проблема с типом общего типа заключается в том, что нет возможности проверить, является ли объект экземпляром, например, TreeNode<Integer> во время выполнения (в отличие от TreeNode<String>), поскольку генерические элементы стираются из типов времени выполнения. Он может проверять только TreeNode, но не тип компонента. Но программисты, возможно, ожидали, что эта проверка и поведение бросания исключений из массивов, так как это нормально работает. Поэтому, чтобы избежать этого неожиданного сбоя, Java запрещает его. (В большинстве случаев вы все равно не столкнетесь с этой проблемой, потому что вы не будете смешивать объекты одного и того же типа, но с разными параметрами типа. Но теоретически можно подойти.)

Конечно, вы можете просто обойти проблему, создав массив типа сырых или подстановочных параметров, а затем перейдя к соответствующему типу, например (TreeNode<Integer>)new TreeNode[5]. Какая разница?Ну, это непроверенный актерский состав, который генерирует предупреждение, и вы, программист, берете на себя ответственность за все небезопасные вещи, которые могут произойти позже. Если это что-то неожиданное, компилятор может сказать: «Мы сказали вам!».

1

Поскольку спецификации языка Java writes:

An array creation expression creates an object that is a new array whose elements are of the type specified by the PrimitiveType or ClassOrInterfaceType.

It is a compile-time error if the ClassOrInterfaceType does not denote a reifiable type (§4.7). Otherwise, the ClassOrInterfaceType may name any named reference type, even an abstract class type (§8.1.1.1) or an interface type (§9).

The rules above imply that the element type in an array creation expression cannot be a parameterized type, other than an unbounded wildcard.

Это мне не ясно, почему они требуют этого. Разумеется, тип компонента массива должен быть доступен во время выполнения, и он будет вводить в заблуждение для программиста, если он отличается от типа, указанного в исходном коде. Рассмотрим:

E[] a = new E[10]; 

Здесь было бы плохо, если бы компилятор использовал стиранию E как тип компонент массива, так как программист может также зависеть от массива, чтобы проверить, что ничего, кроме случаев E хранится в нем ,

Это менее ясно, какой вред будет поступать от разрешения:

List<E>[] lists = new List<E>[10]; 

Единственное, что приходит на ум, что назначение элемента массива составит непроверенного гипсе, потому что массив будет проверить элемент является List, но не то, что это List<E>, и, таким образом, не удается выбросить ArrayStoreException.

На практике вы можете безопасно подавить это предупреждение, если вы все еще знаете, что массив не будет проверять параметры типа его типа компонента.

Смежные вопросы