2013-07-12 7 views
10

のインタフェースに制限しますタイプBのもので、BはクラスSomeClassであり、インターフェースAを実装し、AはGenericsを介してユーザーが提供します。Javaのジェネリックは、私はこれが可能であるかないかどうかわからないんだけど、私が達成したいことはこれです

私はBの生成の仕組みについて尋ねていません - 私はそれを支配しています。私が探しているのは、ジェネリック型の引数<A>をクラスではなくインタフェースに制限する方法です。そのため、クリーンタイプの安全性のために構文B extends SomeClass & Aを使用できます。

これは可能ですか?誰もがこの問題の代替アプローチを認識していますか?


編集:

Bは、ワイルドカードのプレースホルダであることを意図している、クライアントように:私はそれがコメントで混乱を引き起こしているようだとして、私は、非常に明確に自分自身を表現していなかったと思います信頼に基づいてキャストすることなく、SomeClassAの1つのオブジェクトを取得できます。コンパイル時に生成されるため、クライアントはSomeClassAを実装する実際のクラスの名前にアクセスすることはできません。したがって、この型の安全性に関する問題です。

+6

いいえ、それは不可能です。 –

+1

これは私に悲しい顔を与えます:( – torquestomp

+3

答えて

5

このようなコンパイル時の制限を課すことは不可能です。汎用型パラメータは、参照型のスタンドインです。クラス型とインタフェース型を区別しません。タイプパラメタの宣言における追加の境界がインタフェース型でなければならないという事実は単に偶発的なものであり、インタフェースを巧みにタイプする手段としてこれを活用する戦略は、型パラメータcan't be used in multiple boundsという制限によって打ち破られました。

あなたの唯一のオプションは、ルイ・ワッサーマンpointed outようClass.isInterface()を使用して実行時のチェックのために解決するために、またはそれがで渡すものに責任があると、呼び出し元にそれを残すことがある。いずれにせよ、法の期待を明確に文書化していることを確認し、動作。


Bクライアントが信頼に基づいてキャストを行うすることなくSomeClassA両方ある単一のオブジェクトを取得することができるように、ワイルドカードのプレースホルダであることを意図しています。クライアントはSomeClassA

これは私には矛盾のように思えるが、実際の実装クラスの名前にアクセスすることはできません。呼び出し元が評価するものをおそらく知ることができない場合は、Bと宣言する必要はありません。注意:ジェネリックメソッドの呼び出し側は型引数を提供します。だから、Bを決める呼び出し元は、それを基にすることができず、推測することができます。それは決して型安全ではありません。

あなたが本当にあなたのメソッドが返すようにしたいことはSomeClassAの両方でいくつかのタイプであるが、彼らは共通のスーパータイプを共有していないので、これはトリッキーであるように思え:

public static <A> SomeClass&A makeSomeClass(A thing) {...} 

(この

回避方法として、SomeClassと一部のインターフェイスタイプの両方を表す別の方法を検討してください。例えば、候補インタフェースはSomeClassを返すための一般的な方法を持つことができます:

public interface IsSomeClass { 
    SomeClass asSomeClass(); 
} 

public interface Foo extends IsSomeClass { } 

asSomeClassの実装では、実際にはちょうどthisを返します。

public static <A extends IsSomeClass> A makeSomeClass(Class<A> type) {...} 

をそのメソッドの呼び出し元は、いずれかのタイプとして返​​されたオブジェクトを使用することができるだろう:次に、あなたは何ができるのインタフェース自体は、その後、別のオプションを変更することができない場合は

final Foo foo = makeSomeClass(Foo.class); 
final SomeClass someClass = foo.asSomeClass(); 

ラッパークラス、代わりに組成物を使用することである。

final class SomeClassWrapper<A> { 

    private final SomeClass someClass; 
    private final A a; 

    //constructor and getters, etc. 
} 

そしてに実装のインスタンスを割り当てる代わりに、ラッパーのインスタンスを返しますあなたの方法someClassa両方:

public static <A> SomeClassWrapper<A> makeSomeClass(Class<A> type) {...} 
+1

この回答に親切に感謝します。 – jahroy

1

SomeClassは常にクラスである場合は、Javaで何の多重継承がないため、<B extends SomeClass & A>Aは、インターフェースすることができます。 が満足できる唯一の方法は、Aがインターフェイスである場合です。

+0

あなたは見落とされるかもしれませんが、コンパイラーは次のように文句を言います:タイプAはインターフェースではありません。それは束縛されたパラメータとして指定することはできません –

+0

@jahroyと@EJPあなたは 'Aが' A、B extends SomeClass&A>の型パラメータであることを見落としているようです。 –

+0

ええ...あなたは正しいですが、一般的な引数がインターフェイスになることをコンパイラに伝える方法はありませんか? –

1

ここでの問題は、この方法からBを返すことです。

タイプパラメータとしてBを指定しますが、メソッドシグニチャのどこにも表示されません。

引数からの戻り値の型をコンパイラが推測する方法

Bを指定するクライアントコードの機会はありません。

SomeClassまたはAのいずれかを返すようです。

Bのいずれかがフード下にありますが、クライアントコードにはSomeClassまたはAと表示されます。

関連する問題