コンパイラが警告 ("ArrayList
は生の型です。ジェネリック型への参照はArrayList<E>
パラメーター化する必要があります") のみを表示し、コードをコンパイルするのはなぜですか? 実行時にコンパイラがデータを指定されたパラメータ型に型キャストできないため、エラーが発生しないのはなぜですか?
3 に答える
引数のないジェネリック型への参照は、raw 型と呼ばれます。
コンパイラがそれらの使用を許可する唯一の理由は下位互換性です。Java コンパイラの各世代は、古いコードとの下位互換性をできる限り維持しようとします。また、Java 5 でジェネリックが導入されて以来、多くの古いコードではジェネリックが使用されていませんでした。
JLS からの引用 (上記のリンク):
生の型の使用は、レガシー コードの互換性への譲歩としてのみ許可されています。Java プログラミング言語にジェネリクスが導入された後に記述されたコードで生の型を使用することは、強くお勧めできません。Java プログラミング言語の将来のバージョンでは、生の型の使用が禁止される可能性があります。
Sun は および関連するクラスにパラレル ユニバースを導入したくなかったためArrayList
、ジェネリック型情報をコレクション (および他の多くの場所) に追加し、古い非ジェネリック コードをコンパイルできるように JLS を定義することにしました (ただし、警告があります)。
適切に作成された新しいコードでは、古いライブラリや壊れたライブラリの生の型とやり取りしない必要はありません。
配列リストがパラメーター化されていない場合の例を考えてみましょう
ArrayList listOfObjects = new ArrayList();
listOfObjects.add("someStringValue");
listOfObjects.add(new Integer(10));
listOfObjects.add(new Dog());
ここではすべてが有効であるため、listOfObjects には何でも追加できます。
しかし、それをパラメータ化すると、
ArrayList<String> listOfStrings = new ArrayList<String>();
listOfStrings.add("someStringValue");
listOfStrings.add(new Dog()); // Boom, compiler error, can't add dogs into list of strings
ジェネリック コードは、ジェネリックが使用されていないレガシ コードと互換性がある必要があるため、コンパイルは成功します。
また、実行時の型安全性はありません。
コレクションに統一性を持たせるために、ジェネリックが Java に導入されました。
つまり、ジェネリックを使用せずにコレクションをメソッドに渡すと、メソッドはコレクションから要素が取得されたときに何を期待するかわかりません。
たとえば、ジェネリックなしですべての文字列からなるコレクションを渡すと、メソッドは正しくないオブジェクトをそれに挿入する可能性があります。
ジェネリックはコンパイルまでしか利用できません。コンパイル後、" type erasure
" が実行され、すべてのジェネリックがコンパイラによって消去されます。
型消去については、このリンクで説明されています。