泛型類型是經過類型參數化的泛型類或接口,修改如下Box
類以演示此概念。segmentfault
首先檢查一個對任何類型的對象進行操做的非泛型Box
類,它只須要提供兩個方法:set
,它將一個對象添加到box中,get
,它將檢索它:數組
public class Box { private Object object; public void set(Object object) { this.object = object; } public Object get() { return object; } }
因爲它的方法接受或返回一個Object
,因此你能夠自由地傳入任何你想要的東西,前提是它不是一種原始類型,沒法在編譯時沒有辦法驗證如何使用該類,代碼的一部分可能會在box中放置一個Integer
並指望從中獲取Integer
,而代碼的另外一部分可能會錯誤地傳入String
,從而致使運行時錯誤。框架
泛型類使用如下格式定義:函數
class name<T1, T2, ..., Tn> { /* ... */ }
由尖括號(<>
)分隔的類型參數部分跟在類名後面,它指定類型參數(也稱爲類型變量)T1, T2, ...
和Tn
。this
要更新Box
類以使用泛型,能夠經過將代碼「public class Box
」更改成「public class Box <T>
」來建立泛型類型聲明,這引入了類型變量T
,能夠在類中的任何位置使用。編碼
經過此更改,Box
類變爲:code
/** * Generic version of the Box class. * @param <T> the type of the value being boxed */ public class Box<T> { // T stands for "Type" private T t; public void set(T t) { this.t = t; } public T get() { return t; } }
如你所見,全部出現的Object
都被T
替換,類型變量能夠是你指定的任何非基本類型:任何類類型、任何接口類型、任何數組類型,甚至是其餘類型變量。對象
能夠應用相同的技術來建立泛型接口。接口
按照慣例,類型參數名稱是單個大寫字母,這與你已經瞭解的變量命名約定造成鮮明對比,而且有充分的理由:若是沒有這種約定,就很難區分類型變量和普通類或接口名稱。開發
最經常使用的類型參數名稱是:
你將在整個Java SE API和本課程的其他部分中看到這些名稱。
要從代碼中引用泛型Box
類,必須執行泛型類型調用,它將T
替換爲某些具體值,例如Integer
:
Box<Integer> integerBox;
你能夠將泛型類型調用視爲與普通方法調用相似,但不是將參數傳遞給方法,而是將類型參數(在本例中爲Integer
)傳遞給Box
類自己。
類型參數和類型參數術語:許多開發人員互換地使用術語「類型參數」和「類型實參」,但這些術語並不相同,編碼時,提供類型實參以建立參數化類型,所以,Foo<T>
中的T
是類型參數,而Foo<String> f
中的String
是類型實參,本課程在使用這些術語時會遵循此定義。
與任何其餘變量聲明同樣,此代碼實際上並不建立新的Box
對象,它只是聲明integerBox
將保存對「Box of Integer」的引用,這就是Box<Integer>
的讀取方式。
泛型類型的調用一般稱爲參數化類型。
要實例化此類,請像往常同樣使用new關鍵字,但在類名和括號之間放置<Integer>
:
Box<Integer> integerBox = new Box<Integer>();
在Java SE 7及更高版本中,只要編譯器能夠從上下文中肯定或推斷類型參數,就能夠用一組空的類型參數(<>
)替換調用泛型類的構造函數所需的類型參數,這對尖括號<>
非正式地稱爲菱形,例如,你可使用如下語句建立Box<Integer>
的實例:
Box<Integer> integerBox = new Box<>();
有關菱形表示法和類型推斷的更多信息,請參閱類型推斷。
如前所述,泛型類能夠有多個類型參數,例如,OrderedPair
泛型類,它實現了Pair
泛型接口:
public interface Pair<K, V> { public K getKey(); public V getValue(); } public class OrderedPair<K, V> implements Pair<K, V> { private K key; private V value; public OrderedPair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } }
如下語句建立OrderedPair
類的兩個實例:
Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8); Pair<String, String> p2 = new OrderedPair<String, String>("hello", "world");
代碼new OrderedPair<String, Integer>
,將K
實例化爲String
,將V
實例化爲Integer
,所以,OrderedPair
的構造函數的參數類型分別是String
和Integer
,因爲自動裝箱,將String
和int
傳遞給類是有效的。
正如菱形中所提到的,由於Java編譯器能夠從聲明OrderedPair<String, Integer>
推斷出K
和V
類型,因此可使用菱形表示法縮短這些語句:
OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8); OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world");
要建立泛型接口,請遵循與建立泛型類相同的約定。
你還可使用參數化類型(即List<String>
)替換類型參數(即K
或V
),例如,使用OrderedPair<K, V>
示例:
OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));