1

これは、物事をどのように行うかという問題ではありませんどうしてそうなるのかという問題です。

Java の配列は、実行時にコンポーネントの型を認識します。また、型消去のために、ジェネリック型変数の配列オブジェクトを持つことはできません。ジェネリックを含む配列型は許可され、健全な読み取り/書き込みがチェックされます。唯一の問題は、アロケーター式のようです。

Java コンパイラでは、次のことも許可されていないことに注意してください。

Pong<Integer> lotsofpong [] = new Pong<Integer>[100];

...どこにあるPongのは、古いパラメトリック クラスです。ここには未知のものは何もありません。はい、実行時にlotsofpongは単に の配列になりますがPong、コンパイラがコンパイル時の目的で型パラメーターを記憶できない理由がわかりません。これらの型はコンパイル時に存在するため、実際にはそれを覚えています。したがって、唯一の問題は、コンパイル時にアロケーターに特定の汎用パラメーター関連のコンポーネント型を与えることを拒否しているようです。

のパラメーターがPongジェネリック型変数であったとしても、違いはありません。動的配列は依然として の配列でありPong、要素ごとに のサイズが必要でありPong、型パラメーターに依存しません。

はい、それを回避する方法があることを知っています-非パラメトリック型からのキャスト (おそらく SuppressWarning を使用) を使用するかPong<Integer>、非パラメトリック クラスでサブクラス化し、代わりにその型を使用します。しかし、この種のアロケーターが許可されない理由はありますか?

4

1 に答える 1

1

Zeller によって提供されたリンクに基づいています (Josh Bloch - 'Effective Java Book' に基づいています)。

次のコードはコンパイルされるため、配列は安全ではありません。

String strings [] = {"Foo"};
Object objects [] = strings;
objects[0] = 1;

実行時に特別な例外が発生します: java.lang.ArrayStoreException. Java ランタイムは、配列に適切な型を入れたかどうかを実行時にチェックします。

配列をそのスーパー タイプの配列に割り当てることを「共分散」と呼びます。

ジェネリックは、コンパイル時に安全であることが保証されています。

質問で言及したコード スニペットをコンパイルできた場合、次のコードもコンパイルされます。

Pong<Integer> integerPongs [] = new Pong<Integer>[100];
Object objectPongs [] = integerPongs;
objectPongs[0] = new Pong<String>();
Pong<Integer> stringPong = integerPongs[0]; // ClassCastException

私たちのコードは安全ではなくなるため、仕様で禁止されていました。

その理由:

objectPongs[0] = new Pong<String>();

が java.lang.ArrayStoreException をスローしないのは、Generics がコンパイル時のメカニズムであるため、Pong の各インスタンスの実行時の型が常に Pong であるためです。

于 2013-05-27T08:37:14.233 に答える