2011-11-08 134 views
8

這是我編寫的一個例子,它是對我的真實代碼的簡化,所以我很抱歉,如果它是有點人爲的。我想要做的是從單個嵌套類型參數中有效獲取兩個類型參數。我很確定這是不可能的,但我認爲我會試一試。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); 

在我的現實世界的情況下,我的泛型有時可以在implements子句中指定,如

public class Bar implements Baz<String> 

不得不指定第二個類型參數更加痛苦,因爲它感覺就像在我的臉上拋出實現細節。不得不說

Foo<Bar,String> 

當String和Bar之間已經存在關係時,只是看起來不夠雅緻。我得到它的Java,所以隨着領土,但只是好奇,如果有這個解決方案。

回答

6

這是不可能的,我不認爲它是理想的,因爲你現有的類沒有什麼需要不變性。

Foo<T,C extends Collection<T>> 

更一般可以

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

如果唯一的原因有T是允許收集的突變。

注意,如果你很在意不必頻繁指定兩個類型參數,你可以創建一個淺子類:在創建時

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

,你可以使用工廠方法,以避免對雙指定

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

您也可以抽象接口爲interface獲得簡潔的類型,你上面DerivedFoo得到了實惠。

+0

工廠方法的想法很有趣,但它仍然困擾我,該類型被指定兩次即使我的代碼指出,他們總是相同的。 –

+0

@RusselLeggett,好的,所以你需要不變性然後,沒有'收集'?是的。這是一個痛苦。我的建議是處理庫中的複雜性,並嘗試通過讓返回類型爲「interface Foo 」的工廠擴展ComplicatedFoo ,T>'以便客戶端可以使用單參數版本。 –

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。假設我添加了一個getter來再次檢索集合 - 類型會很重要。 –

2

此前Java7,構造不做類型推導,解決辦法是有一個靜態的工廠方法。這不再是必要的。在Java 7中,可以

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

關於TC,如果我們與他們之間的約束2個型參數,有必須是某種程度的冗餘。在你的例子中,由於一個參數C完全決定了另一個參數T,所以冗餘似乎無法忍受。我沒有看到解決方案。

但你可能感覺更好,如果該類型的參數重新排序

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

所以我們聲明String第一;然後進一步提供一個Baz<String>這是Bar