2011-01-20 5 views
15

複数のインタフェースを実装するオブジェクトを返すメソッドを指定することはできますか?複数のインタフェースをフルフィルにするメソッド戻り型

は、我々は次のインタフェースを持っていると言う:FooBar

interface FooBar { 
    [Foo] & [Bar] getFooBar(); 
} 

interface Foo { 
    void doFoo(); 
} 

inteface Bar { 
    void doBar(); 
} 

実装者はFooならびにBarをfullfills型のインスタンスを返すメソッドgetFooBar()を提供する必要があります。

私がこれまで試したどのような

はジェネリックでそれを行うことです:FooAndBarImplは、フレームワークやライブラリによって提供されるいくつかのタイプであると私は動作するはずだと思うFooBarこれを実装していることを考えると

interface FooBar { 
    <T extends Foo & Bar> T getFooBar() 
} 

class SomeImplementor implements FooBar { 
    private FooAndBarImpl fSomeField; 

    public <T extends Foo & Bar> T getFooBar() { 
     return fSomeField; 
    } 

} 

。しかし、 "FooAndBarImplはTに変換できない"ため、そうではありません。何故ですか? getFooBar()で暗示されている契約は、私が見ているように壊れていません。

もう1つの解決策は、FooBarに拡張された新しいインターフェイスを定義し、それを戻り値の型として使用することです。 getFooBar()実装のfSomeFieldの空白のラッパーを返すだけでは意味がありません。

他のアドバイスや説明をありがとうございます。

EDIT:ジェネリック医薬品のアプローチが動作しない理由を誰かが説明できる場合

はそれをお願い申し上げます。私はそれを見ない。

+0

はタイプがフレームワークによって定義されているので(私が考えるもの)ジェネリック医薬品の問題 – davin

答えて

13

あなたはTクラス・パラメータ作ることができます:あなたのジェネリック医薬品のアプローチが機能しなかった理由として

class SomeImplementor<T extends Foo & Bar> implements FooBar { 
    private T fSomeField; 

    public T getFooBar() { 
     return fSomeField; 
    } 

} 

getFooBar()が有効なを持っていないタイプAのオブジェクトを返しますが

SomeImplementor s = new SomeImplementor(); 
A a = s.getFooBar(); 
B b = s.getFooBar(); 

class A implements Bar, Foo{ 
    private int a; 
    ... 
} 
class B implements Bar, Foo{ 
    private String b; 
    ... 
} 
class SomeImplementor implements FooBar { 
    private A someField; 
    public <T extends Foo & Bar> T getFooBar() { 
     return someField; 
    } 
} 

だから我々は今、次のことを実行することができるはずです:FooBarを実装し、次の2つのクラスを作成することができますBが、<T extends Foo & Bar>という要件を満たしているにもかかわらず、タイプBにキャストされています(Stringのメンバーはどこですか?)。つまり有効なTです。要するに

、コンパイラは(ジェネリックがコンパイル時機構であり、覚えて)タイプ<T extends Foo & Bar>のあらゆるTがタイプAのそれへの割り当てを持つことができることを保証することはできません。コンパイラは指定されたAをすべての有効なTに変換できません。

3

また、FooとBarを拡張し、戻り値の型として使用する新しいインターフェイスを定義することもできます。

私はこのオプションを選択します。

+0

のかなり良い説明を含めるとラッパーを作成するために、私の答えを更新しましたか? – z00bs

+0

ラッパーが何を意味するのかよく分かりませんか? 'fSomeField'があなたの新しい結合FooBarインターフェースを実装するもののインスタンスである場合、なぜラッパーを使うのですか? – Brian

+2

タイプはライブラリによって提供されます。つまり、コードを変更することはできません。 – z00bs

2
interface FooBar extends Foo, Bar { 
    FooBar getFooBar(); 
} 
0

FooとBarを提供するコンテナを返すことができます。

public class Container{ 
    private FooBarBam foobar; 
    public Bar asBar(){ 
     return foobar; 
    } 
    public Foo asFoo(){ 
     return foobar; 
    } 
} 

このように、コードでは第3のインターフェイスを実装する必要はありません。欠点は、それが間接指示の追加層であることです。

一般的なアプローチがうまくいかない理由:Tの型を提供する方法がなく、コンパイラはその型を推測できないため、Tを解決することはできません。

davinの回答は良さそうですが、FooとBarを実装するパブリッククラス/インターフェイスも必要です。

更新:

問題は、コンパイラがTのタイプはFooAndBarImplであることを知らない、それは推測しなければならないと推測コンパイラが悪いと予測不可能なコードにつながるということです。

&演算子がサポートされていないので、リストを使用したハッキン​​グも実行されません。ジェネリックのように見えるように実装することは可能ですが、現在は戻り値の型内で複数の境界をサポートしていません。あなたが更新された後

//Does not compile expecting > after Foo 
List<? extends Foo & Bar> getFooBar(){ 
    final List<FooAndBarImpl> l = new ArrayList<FooAndBarImpl>(); 
    l.add(new FooAndBarImpl()); 
    return l; 
} 
+0

これは私が得られないものです:コンパイラは、 'fSomeField'の型が' Foo'と 'Bar'を実装していることを知っていますので、' Foo'と 'Bar'のサブタイプであると推測できますか? – z00bs

関連する問題