2011-11-08 15 views
8

これは私が実際のコードを簡略化した例です。少し工夫すれば謝ります。私がしたいのは、単一の入れ子型引数の中から2つの型パラメータを効果的に取得することです。私はこれが不可能だと確信していますが、私はそれを撃つと思っていました。Javaのネストされた型のパラメータ

//Not legal java code 
public class Foo<C extends Collection<T>> { //where T is another type parameter 
    private C coll; 

    public Foo(C coll) { 
     this.coll = coll; 
    } 

    public void add(T elem){ 
     this.coll.add(elem); 
    } 
    //UPDATED TO ADD GETTER 
    /** 
    * I may need to retrieve the collection again, or pass it 
    * on to another function that needs the specific C type 
    */ 
    public C getColl(){ 
     return coll; 
    } 
} 
... 
List<String> strings = new ArrayList<String>(); 
Foo<List<String>> foo = new Foo<List<String>>(strings); 
foo.add("hello"); 

私は別の型パラメータを追加することによってそれを行うことができることを知っている:

public class Foo<C extends Collection<T>,T> 

が、その後、私は冗長を追加する必要があります。

Foo<List<String>,String> foo = new Foo<List<String>,String>(strings); 

そして、私の現実世界のケースでは、私のジェネリックは、ときどき

のように指定することができます
public class Bar implements Baz<String> 

第2の型のパラメータは、それが私の顔に実装の詳細をスローするように感じるため、さらに痛いと指定する必要があります。文字列とバーとの間の関係がすでに存在するとき

Foo<Bar,String> 

を言うために持つことは、単に洗練ようです。私はそのJavaを取得するので、それは領土と一緒に行くが、これのための解決策があるかどうか不思議です。

答えて

6

既存のクラスに不変性を必要とするものがないため、とにかく理想的ではないと思います。 Tを持っている唯一の理由は、コレクションの変異を可能にしている場合

Foo<T,C extends Collection<T>> 

は、より一般的に

Foo<T,C extends Collection<? super T>> 

である可能性があります。

注意、あなたが頻繁に2種類のパラメータを指定することを懸念している場合、あなたは浅いサブクラスを作成することができます

class DerivedFoo<T> extends Foo<Collection<T>,T> 

、あなたは、作成時にダブルを指定することを避けるためにファクトリメソッドを使用することができます

public static <T> Foo<Collection<T>,T> fromCollection(Collection<T> c) 

またinterfaceへの抽象インタフェースを使用すると、上記のDerivedFooで取得簡潔なタイプのメリットを取得することができます。

+0

です。ファクトリメソッドの考え方は面白いですが、私のコードでは常に同じであることが指示されていますが、型が2回指定されているということはなおも気になります。 –

+0

@RusselLeggett、OK、そうすれば不変性が必要です。コレクションNoはありませんか?うんそれは痛みです。私のアドバイスは、あなたのライブラリの複雑さに対処し、戻り値の型が 'Foo のFactoryがCompleicatedFoo 、T>'を継承するようにして、クライアントが単一パラメータのバージョンを使うことができるようにすることによって簡潔なAPIを公開することです。 –

2

は、なぜあなただ​​けのように、あなただけのタイプパラメータとしてTを使用していないだろう。

public class Foo<T> { //where T is another type parameter 
private Collection<T> coll; 

public Foo(Collection<T> coll) { 
    this.coll = coll; 
} 

public void add(T elem){ 
    this.coll.add(elem); 
} 
+0

これが解決策ではない理由が分かりました。 – ty1824

+3

私が言ったように、それは人為的な例ですが、入ってきたコレクションのタイプも重要な場合はどうでしょうか。それはリスト、セット、TreeListのいずれかです。コレクションを再度取得するためにゲッターを追加したとします。タイプが重要です。 –

2

前Java7に、コンストラクタは、型推論をしない、この問題を回避するには、静的なファクトリメソッドを持つことです。それはもはや必要ではありません。我々はそれらの間の制約を持つ2種類のパラメータを持っている場合は、Java 7ではあなたは、TC

Foo<List<String>,String> foo = new Foo<>(strings); 

についてできる、ある程度の冗長性があるようになりました。あなたの例では、1つのパラメータCが別のパラメータTを完全に指示するので、冗長性は耐え難いようです。私は解決策を見ない。

しかし、あなたはおそらく、型パラメータが

Foo<String,Bar> foo = new Foo<>(bar); 

を並べ替えているのであれば、我々はStringが最初に宣言良く感じることができます。 Baz<String>Bar

関連する問題