2

今日、私は次の問題に遭遇しました。セットアップを検討してください:

interface A {
    void foo();
}

interface B {
    void bar();
}

class Impl implements A,B {

    public void foo() { }
    public void bar() { }

}

class Usage {

    void worksAsParameter(){
        acceptIt(new Impl());
    }

    <T extends A & B> void acceptIt(T foo){

    }

    <T extends A & B> T returnIt(){
        return new Impl(); // <-- Compile error
    }

}

コードは、マークされている最後のステートメントを除いてコンパイルされます。エクリプスは私にerror: Type mismatch: cannot convert from Impl to T

私の質問は次のとおりです:パラメータとして指定された場合にImpl代入可能であるのはなぜですかT(に示されてworksAsParameterいますTが、戻り値nullの型Tである場合はそうではありImplません)。

この質問は、このSOの質問と似ていますが、同じではないことに注意してください。

編集:タイプミスを修正しました。

=== まとめ ===
ジェネリックな戻り値の型がどのように機能するかを誤解していたようです。私はそれについての私の新しい理解を書き込もうとします。
問題を見てみましょう:

<T extends A & B> T returnIt(){
    return new Impl(); // <-- Compile error
}

私の最初の仮定は、実装クラス (この場合は ) が、拡張する必要があるという制限付きUsageの具体的な型を決定し、. どうやら、何が何であるかを決定し、に割り当て可能な値を提供する必要があるのは、呼び出し元/呼び出しサイトです。ただし、コンパイル時の取引のみであるため、(何にでも代入可能であるため) を除いてそのような値を指定することはできません。私の知る限り、これは、フォームのコードは次の値しか返せないことを意味します。TABTUsageTTnullnull

<T extends A> T returnIt(){
    return x; // <-- Compile error
}

うまくいけば、別の設定でより便利になるかなり直観的でない機能。ありがとうピーター!

4

3 に答える 3

4

理由

<T extends A & B> T returnIt(){
    return new Impl();
}

コンパイルしないということは、T が A と B を拡張する任意のクラスである可能性があるということです。たまたま、現時点で可能なクラスは 1 つしかないことを知っていますが、コンパイルはこれを「認識」していません。

例えば

class AB extends A, B { }

Usage usage = ...
AB ab = usage.<AB>returnIt(); // T is AB not Impl.

問題を強制することができます

<T extends A & B> T returnIt(){
    return (T) new Impl(); // unchecked cast warning.
}

しかし、より良い解決策は

Impl returnIt(){
    return new Impl();
}

これは2つのジェネリックを定義します

<T extends A, B>

T extends AそしてまたB extends Object

あなたが意図したかもしれないことは

<T extends A & B>

ここで、T は A と B を拡張する必要があります。

于 2012-09-07T09:05:22.100 に答える
1

次のように使用できます。

   <T extends A, B> T returnIt(){
    return  (T) new Impl(); // <-- cast it to type T
  }
于 2012-09-07T09:10:47.343 に答える
0

コンパイルエラーを回避するために、以下のようなこともできます。

       <T extends A & B> T returnIt(Class<T> type) {
        return type.cast(new Impl());
    }
于 2012-09-07T09:25:27.367 に答える