26

私の知る限り、Java は実行時にジェネリック型引数情報を削除します。コンパイル時にチェックを実行するためにのみ使用されます。たとえば、この特定のメソッド呼び出しが有効かどうかなどです。

今日、私は次のコードに出くわしました。このコードでは、Java がコレクション/リスト型の引数によって、どのコンストラクターを呼び出すかを決定しているようです。

public static class MyClass {
    public MyClass(final Collection<String> coll) {
        System.out.println("Constructor 1");
    }
    public MyClass(final List<Integer> list) {
        System.out.println("Constructor 2");
    }
}

次の呼び出しが行われます。

new MyClass(new HashSet<String>()); // Constructor 1
new MyClass(new ArrayList<String>()); // Constructor 1
new MyClass(new ArrayList<Integer>()); // Constructor 2

ここで、型引数を消去すると:

public static class MyClass2 {
    public MyClass2(final Collection coll) {
        System.out.println("Constructor 1");
    }
    public MyClass2(final List list) {
        System.out.println("Constructor 2");
    }
}

...同じ呼び出しが期待どおりに機能します。リスト引数を使用するコンストラクター呼び出しは、そのニーズを「最も正確に」満たすコンストラクターを対象としています。

new MyClass2(new HashSet<String>()); // Constructor 1
new MyClass2(new ArrayList<String>()); // Constructor 2
new MyClass2(new ArrayList<Integer>()); // Constructor 2

コンパイルされたクラス (この場合は MyClass) にジェネリック情報が格納されており、結局破棄されていないように見えますが、破棄する必要があります。私は何を誤解していますか?

4

3 に答える 3

4

コンストラクタを扱っていることに気づきませんでした。とにかく、以下の引数はコンストラクターに対しても有効です。


オーバーロードされたメソッドのメソッド呼び出しは、コンパイル時にコンパイラによって解決されます。また、ジェネリックはコンパイル時の型チェックにのみ使用されます。したがって、これは完全に実行時のビジネスである型消去とは何の関係もありません。

最初のケースを考えてみましょう:

public MyClass(final Collection<String> coll)
public MyClass(final List<Integer> list)

ここで、メソッドを次のように呼び出すと:

new MyClass(new HashSet<String>()); // Constructor 1
new MyClass(new ArrayList<String>()); // Constructor 1
new MyClass(new ArrayList<Integer>()); // Constructor 2

コンパイラは、渡された引数に対してより具体的な型を持つメソッドを決定します。ケース 2 を考えてみましょう。主な疑問はどこにあると思いますか。

ArrayList<String>は のサブタイプですが、 のサブタイプではありCollection<String>ませんList<Integer>。ジェネリックは不変です。したがって、コンパイラは 2 番目のメソッド呼び出しを最初のメソッドにバインドします。

ここで、生の型を使用している 2 番目のケースを考えてみましょう。

public MyClass2(final Collection coll)
public MyClass2(final List list)

現在、ArrayList<String>Listand Collectionboth のサブタイプです。しかしList、より具体的ArrayListですCollection。したがって、コンパイラはメソッド呼び出しをバインドします。

new MyClass2(new ArrayList<String>());

List引数として取っているもので。


参考文献:

于 2013-08-26T14:47:31.647 に答える
3

簡単に言えば、コンパイラは一致する最も狭い型を選択します。

生のパラメーター バージョンでは、何が選択されるかは明らかですが、ジェネリック バージョンでは、コレクション/リストの型が一致する情報に含まれています。ArrayList は Collection と List の両方ですが、簡単にArrayList の型も比較することで引き分けにします。これで、まだ 1 つのメソッドだけが一致します。

于 2013-08-26T14:46:43.877 に答える