1

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

エラーが発生します。ただし、「newTreeNode[num_of_children]」は機能します。型消去について読んだのですが、なぜうまくいかないのかわかりTreeNode<E>[]ません。何故ですか?教えてください!

4

2 に答える 2

3

Javaのようなものnew TreeNode<String>[]new TreeNode<E>[]Javaによって許可されていません。実行できるのはnew TreeNode[]and new TreeNode<?>[](無制限のワイルドカードパラメーター)だけです。

この理由は少し複雑ですが、有益です。Javaの配列は、実行時にコンポーネントタイプを認識し、何かを入力するたびに、それがコンポーネントタイプのインスタンスであるかどうかを確認し、そうでない場合は例外をスローします(これは、配列タイプが共変であるため、コンパイル時に本質的に安全ではありません)。

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

次に、ジェネリックを追加します。ジェネリックコンポーネントタイプの問題は、ジェネリックがランタイムタイプから消去されるため、オブジェクトがTreeNode<Integer>実行時に(ではなく)インスタンスであるかどうかを確認する方法がないことです。チェックすることはできますが、コンポーネントタイプはTreeNode<String>チェックできません。TreeNodeしかし、プログラマーは、通常は機能するため、配列からのこのチェックと例外スローの動作を期待していた可能性があります。したがって、この予期しない失敗を回避するために、Javaはそれを許可していません。(ほとんどのコードでは、同じタイプで異なるタイプのパラメーターのオブジェクトを混合しないため、この問題が発生することはありません。ただし、理論的には発生する可能性があります。)

もちろん、rawまたはワイルドカードパラメータタイプの配列を作成し、適切なタイプにキャストすることで、問題を簡単に回避できます(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];

頭に浮かぶ唯一のことは、配列が要素がであるとチェックするが、それがであるとはチェックしないため、配列要素を割り当てると、チェックされていないキャストにListなりList<E>、したがって、をスローできないということですArrayStoreException

実際には、配列がそのコンポーネントタイプのタイプパラメータをチェックしないことを認識している限り、この警告を安全に抑制することができます。

于 2012-06-23T08:19:20.553 に答える