ホームページ >Java >&#&チュートリアル >List> でさまざまな種類のネストされたリストが許可されるのはなぜですか?

List> でさまざまな種類のネストされたリストが許可されるのはなぜですか?

Patricia Arquette
Patricia Arquetteオリジナル
2024-11-18 21:38:021012ブラウズ

Why Does a List<List<?>> さまざまな種類のネストされたリストを許可しますか? 
> さまざまな種類のネストされたリストを許可しますか? " />

ジェネリック メソッドでの複数のワイルドカードは Java コンパイラを混乱させる可能性があります

問題:

ジェネリック メソッドでの複数のワイルドカードの使用ジェネリック メソッドは、Java コンパイラとプログラマの両方にとって混乱を引き起こす可能性があります。次の例を考えてみましょう。

public class TwoListsOfUnknowns {
    static void doNothing(List<?> list1, List<?> list2) {}

    public static void main(String[] args) {
        List<String> list1 = null;
        List<Integer> list2 = null;
        doNothing(list1, list2); // compiles fine!
    }
}

List と List を使用して doNothing を呼び出すことができます。ただし、次のバリエーションはコンパイルされません:

public class TwoListsOfUnknowns2 {
    static void doSomethingIllegal(List<?> list1, List<?> list2) {
        list1.addAll(list2); 
            // DOES NOT COMPILE!!!
    }
}

list1 と list2 はまったく異なる型を参照するため、この動作は予期されています。

次のコードでは混乱が生じます:

public class LOLUnknowns1 {
    static void probablyIllegal(List<List<?>> lol, List<?> list) {
        lol.add(list); // this compiles!! how come???
    }
}

このコードはコンパイルできますが、List と List のリストはコンパイルできませんか?

public class LOLUnknowns2 {
    static void rightfullyIllegal(
            List<List<? extends Number>> lol, List<?> list) {

        lol.add(list); // DOES NOT COMPILE! As expected!!!
    }
}

コンパイラはその仕事をしているようですが、次のバリエーションで混乱が続いています:

public class LOLUnknowns3 {
    static void probablyIllegalAgain(
            List<List<? extends Number>> lol, List<? extends Number> list) {

        lol.add(list); // compiles fine!!! how come???
    }
}

List> が含まれる可能性があるため、このコードはコンパイルすべきではないでしょうか; lol と List リスト?

これらの動作を明確にするために、コードを LOLUnknowns1 に戻して、おそらく Illegal を呼び出してみましょう:

public class LOLUnknowns1a {
    static void probablyIllegal(List<List<?>> lol, List<?> list) {
        lol.add(list); // this compiles!! how come???
    }

    public static void main(String[] args) {
        List<List<String>> lol = null;
        List<String> list = null;
        probablyIllegal(lol, list); // DOES NOT COMPILE!!
    }
}

両方で同じ型でもワイルドカードを使用すると、コードはコンパイルされません。ただし、最初の引数の null 型はコンパイルされます:

public class LOLUnknowns1b {
    static void probablyIllegal(List<List<?>> lol, List<?> list) {
        lol.add(list); // this compiles!! how come???
    }

    public static void main(String[] args) {
        List<String> list = null;
        probablyIllegal(null, list); // compiles fine!
    }
}

答え:

この混乱は、List< などのネストされたワイルドカードとは何かについての誤解から生じています。 ;List>、実際には、という意味です。 Java ジェネリックは不変です。つまり、ジェネリックのインスタンス化では型間の関係が保持されません。これはネストされたリストにも当てはまります。

A List<String> is (captureable by) a List<?>.
A List<List<String>> is NOT (captureable by) a List<List<?>>.
A List<List<String>> IS (captureable by) a List<? extends List<?>>.

したがって、List>要素が任意の型のリストであるリストを表します。特に同じ型ではありません。これは、次のコードが正当であることを意味します。

List<List<?>> lolAny = new ArrayList<>();

lolAny.add(new ArrayList<Integer>());
lolAny.add(new ArrayList<String>());

要約

複数の汎用ワイルドカードを使用した Java コンパイラの動作は、キャプチャ変換ルールによって決まります。混乱を避けるためには、ワイルドカード キャプチャの制限を理解することが重要です。

以上がList> でさまざまな種類のネストされたリストが許可されるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。