1. ホーム
  2. java

[解決済み] 一般的な戻り値の上限 -インターフェースとクラスの比較 - 意外と有効なコード

2022-04-22 22:15:31

質問

これはサードパーティのライブラリAPIからの実際の例ですが、簡略化されています。

Oracle JDK 8u72 でコンパイルされています。

この2つの方法について考えてみましょう。

<X extends CharSequence> X getCharSequence() {
    return (X) "hello";
}

<X extends String> X getString() {
    return (X) "hello";
}

どちらも "unchecked cast" という警告が表示されます - 理由はわかりました。私が困惑しているのは、なぜ私が

Integer x = getCharSequence();

で、コンパイルは?コンパイラは Integer は実装されていません。 CharSequence . への呼び出しは

Integer y = getString();

を実行すると、(予想通り)エラーが発生します。

<ブロッククオート
incompatible types: inference variable X has incompatible upper bounds java.lang.Integer,java.lang.String

なぜこの動作が有効だと考えられるのか、誰か説明してください。どのように役に立つのでしょうか?

クライアントはこの呼び出しが安全でないことを知りません。クライアントのコードは警告なしにコンパイルされます。なぜコンパイルはそのことについて警告を出したり、エラーを出したりしないのでしょうか?

また、この例とどう違うのでしょうか。

<X extends CharSequence> void doCharSequence(List<X> l) {
}

List<CharSequence> chsL = new ArrayList<>();
doCharSequence(chsL); // compiles

List<Integer> intL = new ArrayList<>();
doCharSequence(intL); // error

パスしようとする List<Integer> は、予想通りエラーが発生します。

method doCharSequence in class generic.GenericTest cannot be applied to given types;
  required: java.util.List<X>
  found: java.util.List<java.lang.Integer>
  reason: inference variable X has incompatible bounds
    equality constraints: java.lang.Integer
    upper bounds: java.lang.CharSequence

それがエラーとして報告された場合、なぜ Integer x = getCharSequence(); はないのですか?

解決方法は?

CharSequenceinterface . したがって、たとえ SomeClass は実装されていません。 CharSequence を作成することは完全に可能です。

class SubClass extends SomeClass implements CharSequence

したがって、次のように書くことができます。

SomeClass c = getCharSequence();

というのは、推論された型が X は交差型 SomeClass & CharSequence .

の場合、少し変です。 Integer なぜなら Integer はfinalですが final は、これらのルールでは何の役割も果たしません。例えば、次のように書くことができます。

<T extends Integer & CharSequence>

一方 Stringinterface を拡張することは不可能です。 SomeClass のサブタイプを取得するために String なぜなら、javaはクラスの多重継承をサポートしていないからです。

を使用すると List の例では、ジェネリックスは共変でも共変量でもないことを覚えておく必要があります。つまり、もし X のサブタイプです。 Y , List<X> のサブタイプでもスーパータイプでもありません。 List<Y> . というのも Integer は実装されていません。 CharSequence を使用することはできません。 List<Integer> の中に doCharSequence メソッドを使用します。

しかし、これをコンパイルすることは可能です。

<T extends Integer & CharSequence> void foo(List<T> list) {
    doCharSequence(list);
}  

というメソッドがある場合 を返します。 a List<T> のようになります。

static <T extends CharSequence> List<T> foo() 

できること

List<? extends Integer> list = foo();

ここでも、推論された型が Integer & CharSequence のサブタイプであり、これは Integer .

複数の境界を指定した場合、暗黙のうちに交差型が発生する(例. <T extends SomeClass & CharSequence> ).

詳しくはこちら こちら は、JLSで型境界がどのように機能するかを説明している部分です。複数のインターフェイスを含めることができる、例えば

<T extends String & CharSequence & List & Comparator>

が、最初のバウンドだけが非インターフェイスである可能性があります。