我們?cè)谏厦嫣岬搅? List> 中的元素只能使用 Object 來引用, 這樣作肯定時(shí)不太方便的, 不過幸運(yùn)的是, Java 的泛型機(jī)制允許我們對(duì)泛型參數(shù)的類型的上界和下界做一些限制, 例如 List extends Number> 定義了泛型的上界是 Number, 即 List 中包含的元素類型是 Number 及其子類. 而 List super Number> 定義了泛型的下界, 即 List 中包含的是 Number 及其父類. 當(dāng)引入了泛型參數(shù)的上界和下界后, 我們編寫代碼相對(duì)來說就方便了許多, 不過也引入了新的問題, 即我們?cè)谑裁磿r(shí)候使用上界, 什么時(shí)候使用下界, 以及它們的區(qū)別和限制到底時(shí)什么? 下面我來說說我的理解.
? extends T
? extends T 描述了通配符上界, 即具體的泛型參數(shù)需要滿足條件: 泛型參數(shù)必須是 T 類型或它的子類, 例如:
List extends Number> numberArray = new ArrayList(); // Number 是 Number 類型的
List extends Number> numberArray = new ArrayList(); // Integer 是 Number 的子類
List extends Number> numberArray = new ArrayList(); // Double 是 Number 的子類
上面三個(gè)操作都是合法的, 因?yàn)?? extends Number 規(guī)定了泛型通配符的上界, 即我們實(shí)際上的泛型必須要是 Number 類型或者是它的子類, 而 Number, Integer, Double 顯然都是 Number 的子類(類型相同的也可以, 即這里我們可以認(rèn)為 Number 是 Number 的子類).
G extends SubClass> 是 G extends SuperClass> 的子類型. 如 List extends Integer> 是 List extends Number> 的子類型
G 是 G extends SuperClass> 的子類型, 例如 List 是 List extends Integer> 的子類型.
G> 和 G extends Object> 等同.
可以想象 G extends T> 為一個(gè)左閉右開的區(qū)間(T 在最左邊), G extends Object> 是最大的區(qū)間, 當(dāng)區(qū)間 G extends SuperClass> 包含 區(qū)間 G extends SubClass>時(shí), 那么較大的區(qū)間就是父類.
關(guān)于讀取
根據(jù)上面的例子, 對(duì)于 List extends Number> numberArray 對(duì)象:
我們能夠從 numberArray 中讀取到 Number 對(duì)象, 因?yàn)?numberArray 中包含的元素是 Number 類型或 Number 的子類型.
根據(jù)上面的例子, 對(duì)于 List extends Number> numberArray 對(duì)象:
我們不能添加 Number 到 numberArray 中, 因?yàn)?numberArray 有可能是List 類型
我們不能添加 Integer 到 numberArray 中, 因?yàn)?numberArray 有可能是 List 類型
我們不能添加 Double 到 numberArray 中, 因?yàn)?numberArray 有可能是 List 類型
即, 我們不能添加任何對(duì)象到 List extends T> 中, 因?yàn)槲覀儾荒艽_定一個(gè) List extends T> 對(duì)象實(shí)際的類型是什么, 因此就不能確定插入的元素的類型是否和這個(gè) List 匹配. List extends T> 唯一能保證的是我們從這個(gè) list 中讀取的元素一定是一個(gè) T 類型的.
? super T
? super T 描述了通配符下界, 即具體的泛型參數(shù)需要滿足條件: 泛型參數(shù)必須是 T 類型或它的父類, 例如:
// 在這里, Integer 可以認(rèn)為是 Integer 的 "父類"
List super Integer> array = new ArrayList();
// Number 是 Integer 的 父類
List super Integer> array = new ArrayList();
// Object 是 Integer 的 父類
List super Integer> array = new ArrayList();
關(guān)于讀取
對(duì)于上面的例子中的 List super Integer> array 對(duì)象:
我們不能保證可以從 array 對(duì)象中讀取到 Integer 類型的數(shù)據(jù), 因?yàn)?array 可能是 List 類型的.
我們不能保證可以從 array 對(duì)象中讀取到 Number 類型的數(shù)據(jù), 因?yàn)?array 可能是 List 類型的.
有一點(diǎn)需要注意的是, List super T> 和 List extends T> 中, 我們所說的 XX 是 T 的父類(a superclass of T) 或 XX 是 T 的子類(a subclass of T) 其實(shí)是針對(duì)于泛型參數(shù)而言的. 例如考慮如下例子:
List super Integer> l1 = ...
List extends Integer> l2 = ...
那么這里 ? super Integer 和 ? extends Integer 的限制是對(duì)誰(shuí)的呢? 是表示我們可以插入任意的對(duì)象 X 到 l1 中, 只要 X 是 Integer 的父類? 是表示我們可以插入任意的對(duì)象 Y 到 l2 中, 只要 Y 是 Integer 的子類? 其實(shí)不是的, 我們必須要拋棄上面的概念, ? super Integer 和 ? extends Integer 限制的其實(shí)是 泛型參數(shù), 即 List super Integer> l1 表示 l1 的泛型參數(shù) T 必須要滿足 T 是 Integer 的父類, 因此諸如 List, List 的對(duì)象就可以賦值到 l1 中. 正因?yàn)槲覀冎懒?l1 中的泛型參數(shù)的邊界信息, 因此我們就可以向 l1 中添加 Integer 對(duì)象了, 推理過程如下:
令 T 是 l1 的泛型參數(shù), 即:
l1 = List = List super Integer>
因此有 T 是 Integer 或 Integer 的父類.
如果 T 是 Integer, 則 l1 = List, 顯然我們可以添加任意的 Integer 對(duì)象或 Integer 的子類對(duì)象到 l1 中.
如果 T 是 Integer 的父類, 那么同理, 對(duì)于 Integer 或 Integer 的子類的對(duì)象, 我們也可以添加到 l1 中.
按同樣的分析方式, List extends Integer> l2 表示的是 l2 的泛型參數(shù)是 Integer 的子類型. 而如果我們要給一個(gè) List 插入一個(gè)元素的話, 我們需要保證此元素是 T 或是 T 的子類, 而這里 List extends Integer> l2, l2 的泛型參數(shù)是什么類型我們都不知道, 進(jìn)而就不能確定 l2 的泛型參數(shù)的子類是哪些, 因此我們就不能向 l2 中添加任何的元素了.
Producer extends: 如果我們需要一個(gè) List 提供類型為 T 的數(shù)據(jù)(即希望從 List 中讀取 T 類型的數(shù)據(jù)), 那么我們需要使用 ? extends T, 例如 List extends Integer>. 但是我們不能向這個(gè) List 添加數(shù)據(jù).
Consumer Super: 如果我們需要一個(gè) List 來消費(fèi) T 類型的數(shù)據(jù)(即希望將 T 類型的數(shù)據(jù)寫入 List 中), 那么我們需要使用 ? super T, 例如 List super Integer>. 但是這個(gè) List 不能保證從它讀取的數(shù)據(jù)的類型.
public class Collections {
public static void copy(List super T> dest, List extends T> src)
{
for (int i=0; i
上面的例子是一個(gè)拷貝數(shù)據(jù)的代碼, src 是 List extends T> 類型的, 因此它可以讀取出 T 類型的數(shù)據(jù)(讀取的數(shù)據(jù)類型是 T 或是 T 的子類, 但是我們不能確切的知道它是什么類型, 唯一能確定的是讀取的類型 is instance of T), , dest 是 List super T> 類型的, 因此它可以寫入 T 類型或其子類的數(shù)據(jù).
摘要:定義具有一個(gè)或多個(gè)類型變量的類,稱之為泛型類。泛型類的繼承創(chuàng)建對(duì)象的兩種方式錯(cuò)誤方式錯(cuò)誤原因繼承了泛型類,但并不是泛型類,所以不能這樣創(chuàng)建對(duì)象。同樣是泛型類,它的父類也是泛型類,它傳遞的是常量。
泛型類
public class A {
//在成員變量上使用泛型
private T t;
public A() {}
//構(gòu)造參數(shù)類型上...