2012-02-22 81 views
8

考慮下面的構造函數的類Foo(爲了清楚起見是泛型類):什麼是泛型構造函數的用例?

public <T> Foo(T obj) { } 

這是構造有效的語法,就像正常generic methods

但是這個語法的用法是什麼?通常泛型方法爲其返回類型提供了類型安全性,並且可以受益於編譯器的類型推斷。例如:

Pair<String, Integer> stringInt = Pair.of("asfd", 1234); 

,但對一個構造函數的調用總是返回其聲明類的一個實例,因此它的類型參數的返回類型沒有影響。上面的構造可能只是其erasure取代:

public Foo(Object obj) { } 

當然泛型的不僅是關於返回類型類型安全。構造函數可能只是想約束參數(S)的類型被傳遞但是,上述理由仍適用於有限制類型參數:

public <N extends Number> Foo(N number) { } 

public Foo(Number number) { } //same thing 

即使嵌套類型參數與邊界使用通配符處理:

public <N extends Number, L extends List<N>> Foo(L numList) { } 

public Foo(List<? extends Number> numList) { } //same thing 

那麼具有泛型構造函數的合法用例是什麼?

回答

6

這是一個可能的改編自函數式編程的函數。假設我們有一個Stream類型,它有一些內部狀態,重複產生新的元素,直到它返回null。外部來電者不關心流類型的內部狀態的類型是什麼,所以你可能會喜歡

class Stream<E> { 
    <S> Stream(S initialState, StepFunction<E, S> stepFun) { 
    ... 
    } 
} 

的東西,而不必知道的內部狀態是什麼類型的收件人。

+0

啊哈,很有意思! +1 – 2012-02-22 23:16:49

+0

+1,這是一個很好的例子,雖然它有點作弊,因爲OP特別說封閉類型不是通用的。 ('Stream '將是通用的。) – 2012-02-22 23:23:25

+0

@JohnFeminella - 我只是說我的具體例子'Foo'不是通用的,只是爲了避免混淆。我不是說它是對答案的限制。 – 2012-02-22 23:27:59

2

我能想到的一個用例是當您想將構造函數參數約束爲多個類型時。只有通用語法允許你聲明一個構造採取NumberList s表示也實現RandomAccess

public <L extends List<? extends Number> & RandomAccess> Foo(L raNumList) { } 

... 

Foo f1 = new Foo(new ArrayList<Integer>()); 
Foo f2 = new Foo(new LinkedList<Integer>()); //compiler error 
+1

或者爲了與預先通用代碼的向後兼容性,其中'Foo'採用了'Object',但現在你想要一些更專業的東西。 '> >> Foo(T obj)'。 /沒有真正相信任何這一點都很常見。 – 2012-02-23 00:23:28

5

有一件事我能想到我頭頂的是,你可以確保邊界在滿足跨越多個參數的方式相同。

拿一個明顯的愚蠢和做作,但有效的構造函數,複製從源到目標列表:

public <T> Foo (List<T> listA, List<T> listB) { 
    listA.addAll(listB); 
} 

使用通配符這裏很快就會變得非常討厭,你想要什麼反正大概不會做。禁止它也完全是任意的限制。所以語言規範允許它對我有意義。

+2

或在主體內使用'T':' Foo(列表 ts){T t0 = ts.get(0); ts.set(0,ts.get(1)); ts.set(1,t0); }'。好的,不是一個令人信服的例子。 – 2012-02-23 00:23:53

1

您可以爲構造函數參數強制執行某些約束。例如。以下代碼需要兩個實現接口InterfaceA和InterfaceB的參數。

<T extends InterfaceA & InterfaceB > Foo(T t1, T t2) { 

} 
1

主要用途是確保在多個參數之間滿足類型約束。下面是按照正確的順序把一束組件裝配線上的一個示例:

public <T> AssemblyLine(T[] starting, List<T> components) { 
    T[] a = components.toArray(starting); 
    Arrays.sort(a); 
    this.conveyorBelt.add(a); 
} 

這裏<T>確保T[]List<T>保持相同類型T,而不是(例如),Integer[]List<string>

+0

+1我忘記了泛型數組和需要傳遞一個實例,等等 - 很好(我認爲有一個錯字 - 它應該是'components.toArray') – 2012-02-22 23:19:06

+0

謝謝!我解決了這個問題。 – 2012-02-22 23:27:27

相關問題