3

次の例を考えてみましょう。

class ClsA {}
class ClsB {}

interface IntA {}
interface IntB {}

そして、私は2つの非常によく似た方法を持っています:

static <T extends ClsA> T returnC() { // Here T extends the class
    return null;
}

static <T extends IntA> T returnI() { // Here T extends the interface
    return null;
}

そして、メソッドは次を呼び出します。

ClsA ac = returnC(); // This works fine based on inference.

IntA ai = returnI(); // Similarly this works fine based on inference.

ただし、以下の 2 を考慮してください。

ClsB bc = returnC(); // ERROR as expected.

日食エラー:

範囲の不一致: 型 Testing のジェネリック メソッド returnC() は、引数 () には適用できません。推論されたタイプ ClsB&ClsA は、制限付きパラメーターの有効な代替ではありません<T extends ClsA>

しかし、次のコードは正常にコンパイルされます。

IntB bi = returnI(); // Works fine

インターフェイスの場合、バインドされたジェネリックが戻り値の型で考慮されないのはなぜですか?

4

1 に答える 1

1

ここでの魔法の言葉はraw多重継承です。

最初にあなたのreturnC方法を見てみましょう:

static <T extends ClsA> T returnC() {
    return null;
}

つまり、生のメソッドを呼び出すと、戻り値の型は単に になりTます。ClsA returnCClsA

このステートメントがある場合は真です。メソッドの生の戻り値の型が であり、 の型と互換性があるClsA ac = returnC();ため、コンパイラはコンパイルに成功します。ClsAac

生の戻り値の型も、ステートメントClsB bc = returnC();がコンパイルされない理由です。


returnIそれでは、メソッドを見てみましょう。

static <T extends IntA> T returnI() { // Here T extends the interface
    return null;
}

ここで、型パラメーターはのみにバインドされIntAます。

ただし、これは、の置換型がTのみ実装する必要があることを意味するものではありません。IntA型は同時に実装できます。型は複数のインターフェイスを実装できますが、複数のクラスを実装することはできないため、次のようなステートメントは許可されます。IntAIntBIntB bi = returnI();

このクラスを考えてみましょう:

class SomethingReallyCool implements IntA, IntB { }

この型は型パラメータの有効な代替でreturnI()あり、その証明は次のステートメントです。

IntB bi = YourClass.<SomethingReallyCool>returnI();

なんで?これは実装するクラスでIntAあり、コンパイラが気にするのはこれだけだからです。

于 2015-12-03T12:01:41.730 に答える