3

「Thinking in Java 4th edition」のジェネリックの章を読んでいますが、例があります。

class Fruit{}
class Apple extends Fruit {}   

...

static <T> void writeExact(List<T> list, T item) {
            list.add(item);
    }

    static List<Apple> apples = new ArrayList<>();
        static List<Fruit> fruit = new ArrayList<>();

        static void f1() {
            writeExact(apples, new Apple());
            // writeExact(fruit, new Apple()); // Error:
            // Incompatible types: found Fruit, required Apple
        }

        static <T> void writeWithWildcard(List<? super T> list, T item) {
            list.add(item);
        }

        static void f2() {
            writeWithWildcard(apples, new Apple());
            writeWithWildcard(fruit, new Apple());
        }

エラーが示されているこれらのコメント行は、Java 6 と 7 の両方でまったくエラーを生成しません。writeExactメソッドは正確なタイプのパラメーターのみを受け入れるため、私には奇妙に思えます。では、なぜ機能するのでしょうか。スーパータイプのワイルドカードの目的は何ですか?

編集

もう1つ明確にしたいのは、ワイルドカードを使用した型推論のボスは誰ですか? 戻り値の型、最初のパラメーター、2 番目のパラメーター、... . つまり、 SomeClass.< Fruit >method(...) が指定されていない場合

4

2 に答える 2

2

TinwriteExactはメソッド自体の型変数であるため、機能します。ほら、それは void 戻り値の型のすぐ前にあります:

static <T> void writeExact(List<T> list, T item)

つまり、呼び出すたびにT、引数が存在する限り、引数を受け入れるために必要な型を取得します。任意のリストとそのリストに収まるオブジェクトで呼び出すことができます。

おそらく、コンパイラに推論させるのではなく、型引数を明示的に指定する方が明確になります(静的メソッドに対してこれを行うには、クラスの名前を使用する必要があります。私はそれが であると仮定しますMyClass):

        MyClass.<Apple>writeExact(apples, new Apple());
        MyClass.<Fruit>writeExact(fruit, new Apple());

2 番目の呼び出しでTは、値が になりますFruit。つまり、最初の引数は である必要がList<Fruit>あり、2 番目の引数は である必要があります。これは、が のサブタイプであるFruitためです。AppleFruit

型引数を暗黙的に割り当てる規則は、Java 言語仕様のセクション 15.12.2.7 に記載されています。少なくとも、そうだと思います。それは正確に読むのが簡単ではありません。

本のコードは、上記のコードとまったく同じではないと思います。もしそうなら、それは間違いであり、エッケル氏に手紙を書いて彼に伝えるべきです.

于 2012-11-04T21:40:54.050 に答える
1
static <T> void writeExact(List<T> list, T item) {
            list.add(item);
    }

パラメータ化された型Tで宣言したため、 (List of Applies,Apple または List of Fruits, Fruit または List of Apples, Fruit (Fruit は apple のサブタイプであるため)) を受け入れます。

于 2012-11-04T21:40:10.023 に答える