眾所週知,Java跟C#都是從C++演變而來。
既然C++有Template
,Java在5.0,C#在2.0的時期分別引進了Generics
,
雖然看起來很像,看其中差異還是不小,列出重要的幾點份來討論。
Generics不能接受Nontype Parameter
由於實作方式的不同,Generics拿掉了這個
1 | template <typename T, int MAXSIZE> class Stack { |
Generic不支援Specialization
不管是Full Specialization或是 Partial Specialization,通通不行。所以也寫不出這樣的程式碼。
1 | template <typename T> class Foo {}; |
Template不對Type作任何限制,而Generics能擁有Bound Type
這點才是最大的不同,假設我們要寫一個兩樹相加的Generic function。
在C++我們會這麼寫
1 | template <typename T> T sum2(T a, T b) { return a + b; } |
可以看到,只要有定義operator+
,我們什麼東西都能相加。
同樣的Code,如果改寫成C#的話
1 | public static T sum2<T>(T a, T b) |
連編譯都邊不過。原因出在Template是在Compile-Time完成的,在編譯的時刻就能檢查出operator+
是否存在,而Java跟C#的Generics是在Runtime則否,必須對Type有其一定的限制,在這個範例裡面,我們需要這個Type要有相加的能力,才能作相加的動作。
1 | public <T extends Number> T sum(T a, T b) { |
所有從Number衍生出來的子類別,Integer,Double等都可以使用,不過String不行。
不過.Net 4.0之後有更好的解法,掠過編譯時期的型別檢查,不過Java沒有此特性。
1 | public static T sum2<T>(T a, T b) |
Template不支援Covariance和Contravariance
這是另一個大題目,同樣在.Net 4.0之後,支援了Covariance和Contravariance。Java的版本有無支援也需要確認。
以後有時間再仔細描述。在C#可以寫這樣的Code
1 | class Base |
類似的程式碼在C++就失敗了…
1 | class Animal |
其他Template高級技巧
例如SFINAE,Template Template Parameter等,由於學習門檻相當高,所以Generics都把它拿掉了。