Javaジェネリックの型消去: いつ、何が起こるのか? 質問する

Javaジェネリックの型消去: いつ、何が起こるのか? 質問する

Javaの型消去について読んだOracleのウェブサイト

型の消去はいつ発生しますか?コンパイル時ですか、それとも実行時ですか? クラスがロードされたときですか? クラスがインスタンス化されたときですか?

多くのサイト (上記の公式チュートリアルを含む) では、型の消去はコンパイル時に行われると書かれています。コンパイル時に型情報が完全に削除される場合、ジェネリックを使用するメソッドが型情報なしまたは間違った型情報で呼び出されたときに、JDK はどのようにして型の互換性をチェックするのでしょうか。

次の例を考えてみましょう。クラスAにメソッドがあるとしますempty(Box<? extends Number> b)。コンパイルしA.javaてクラス ファイルを取得しますA.class

public class A {
    public static void empty(Box<? extends Number> b) {}
}
public class Box<T> {}

ここで、パラメータ化されていない引数 (raw 型) でBメソッドを呼び出す別のクラスを作成します: 。クラスパス内で をコンパイルすると、javac は警告を出すほど賢いです。そのため、いくつかの型情報がその中に保存されますemptyempty(new Box())B.javaA.classA.class

public class B {
    public static void invoke() {
        // java: unchecked method invocation:
        //  method empty in class A is applied to given types
        //  required: Box<? extends java.lang.Number>
        //  found:    Box
        // java: unchecked conversion
        //  required: Box<? extends java.lang.Number>
        //  found:    Box
        A.empty(new Box());
    }
}

私の推測では、型消去はクラスがロードされたときに発生すると思いますが、これは単なる推測です。では、いつ発生するのでしょうか?

ベストアンサー1

型消去はジェネリックの使用に適用されます。クラス ファイルには、メソッド/型がジェネリックであるかどうか、制約は何かなどを示すメタデータが確実に存在します。ただし、ジェネリックが使用されると、コンパイル時のチェックと実行時のキャストに変換されます。したがって、次のコードは次のようになります。

List<String> list = new ArrayList<String>();
list.add("Hi");
String x = list.get(0);

コンパイルされる

List list = new ArrayList();
list.add("Hi");
String x = (String) list.get(0);

T=String実行時にリスト オブジェクトについてそれを確認する方法はありません。その情報は失われます。

...しかし、List<T>インターフェース自体は依然として汎用的であると宣伝されています。

編集: 明確にするために、コンパイラは特定のケースで変数の型引数に関する情報を保持しますが、T=Stringリスト オブジェクト自体についてはそれを見つけることはできません。

おすすめ記事