// 1.协变范例
List<? extends Number> num = new List<Double>();
// 2.逆变范例
List<? super Number> num = new List<Object>();
但是在第一種情況就不能呼叫參數裡帶有?的函數了,例如:
class Container<E> {
E data;
public set(E data) {
this.data = data;
}
public E get(E data) {
return data;
}
}
// 某方法中
Container<? extends Number> num = new Container<Double>();
num.set(new Float(3)); // 编译时错误
這裡同樣是為了保證Type Safety。不能把Float傳給Container<Double>。
同理,在逆變的時候就不能呼叫回傳值帶?的函數,除非接受回傳值的變數型別是Object。
Container<? super Number> num2;
Number res = num2.get(); // 编译时错误
注意對比的對象
A是B的子類別 是A與B在比較
而
List<A>
是List<B>
的子類別 是List與List比較你可以透過
List<? extend b>
這樣的定義 來進行限定操作因為都是List類,又沒有繼承關係
物件的繼承代表了一種‘is-a’的關係,如果兩個物件A和B,可以表達為‘B是A’,則表示B可以繼承A。繼承者也可以理解為是對被繼承者的特殊化,因為它除了具備被繼承者的特性外,還具備自己獨有的個性。
父類和子類,或稱為基類和衍生類,其中子類繼承父類的所有特性,同時也定義新的特性。
List<A>
的子類別是class XXX extends List<A>
Java裡的泛型是透過 型別擦除 來實現的
以下僅供參考 我C++不熟
你不是跟C++模板搞混了?
C++的泛型實作方式不同
因為
List<A>.class
不成立。泛型
一大堆回答都沒講到重點啊。 。我來加點內容。這裡涉及到兩個概念:協變與逆變。 (Covariance vs. Contravariance)
簡言之,如果
List<S>
複合型別是協變的,那麼如果S
是T
的子類,則List<S>
也是List<T>
的子類。如果List<S>
是逆變的,結果顛倒,List<T>
會變成List<S>
的子類別。但是Java裡的泛型不實作以上兩種行為的任一種。 。 Java的泛型是不變的(Invariance)。
為什麼這麼設計呢?先看一個陣列的例子。在Java中,陣列是協變的,於是
Integer[]
就是Number[]
的子類別了。於是我們能寫出這樣的程式碼:Java的型別安全(Type Safety)的保證已經被破壞了。 Java會把數組的元素應有型別保存起來(Reification),保證能在執行時偵測到這種非法操作。
假設List是協變的,那麼如下把Float放進Integer的程式碼:
就能運作。而 @dkmeteor 也提到,Java的泛型採用了型別擦除,這樣就沒辦法保證List裡會不會被塞進一個Float,因為在運行時List看到的全都是Object。因此為了防止這類事情發生,Java的泛型是不變的。
那有沒有辦法在Java裡用上協變或逆變的泛型呢?答案是肯定的,需要在聲明裡加wildcard:
但是在第一種情況就不能呼叫參數裡帶有
?
的函數了,例如:這裡同樣是為了保證Type Safety。不能把
Float
傳給Container<Double>
。同理,在逆變的時候就不能呼叫回傳值帶
?
的函數,除非接受回傳值的變數型別是Object。部分來源:http://www.ibm.com/developerworks/cn/java/j-jtp01255.html