當我們在定義類,接口和方法時,可以接收一個類型作為參數,這就叫做泛型。
函數可以傳入普通的參數,也可以傳入一個類型參數。不同之處是普通的參數就是值而已,但是類型參數卻是個類型。
使用泛型的好處:
強類型檢查。在編譯時就可以得到類型錯誤資訊。
避免顯式強制轉換。
友善實作通用算法。
我們可以建立一個簡單的Class Box。它提供存取一個類型為Object的對象。
你可以傳給它任何你想要的對象,比如對象String,Integer等,也可以傳入自定義的一些對象。但是調用getObject方法傳回的對象需要顯式的強轉為傳入的類型,才能使用原來類型的一些方法。
我們可以使用泛型來構造這個對象。
我們可以看到,所有的Object被替換成了T。T代表了某種類型,你在執行個體化Box對象時,必須要給其指定一種類型,String,Integer或者自定義的類,并且調用getObject方法并不需要進行強轉就可以使用該類型的方法。
一般來說,類型參數名稱越簡單越好,并且需要是大寫的。為了友善,我們約定了一些命名使用。
E Element
K key
N Number
T type
V value
S,U,V 第2,3,4個類型
我們可以這樣執行個體化一個Box類。
同樣,我們也支援在一個類中傳入多個類型參數。例如下面的Pair對象
使用方法如下。
泛型可以作用與方法上,此時泛型參數隻能在方法體中使用。而泛型作用于類時,則在整個類中可以使用。
在靜态方法、非靜态方法及構造函數都可以使用泛型。
下面是對該靜态方法的使用。
預設情況下如果直接使用的話,我們可以給其傳任何值。有時候我們想值允許傳入某個類及它的子類。這時候在聲明泛型時可以使用extends關鍵字。
我們也可以給類型參數加多個限定。
加上限定類或接口以後,我們可以使用泛型參數變量調用該類或接口的方法。
Java中的List就是一個實作了泛型的類,假如我們寫了一個方法,擷取List中元素的個數。隻不過這個方法限定T類型為Number。
然後我們這樣試圖調用它。
為什麼會産生錯誤那?因為我們要求方法的參數是List,而我們實際傳入的是List。雖然Integer是Number的子類,但是List卻不是List的子類,他們其實是平等的關系。這點一定要注意。我們在方法定義時已經明确表示T的類型是Number了,是以隻能接收List,而不能接收其它類型的參數。
這時候<code>?</code>通配符就起作用了。我們可以使用<code>?</code>通配符重新定義這個方法。
既然能限定到一個類及其子類上,當然也能限定到一個類及其父類上。文法如下:
類型參數不能是原始類型(int, char,double),隻能傳入這些類型的封轉類(Integer,Char,Double)。
不能直接建立類型參數的執行個體。
但有通過反射可以實作。
你可以這樣調用它:
靜态字段的類型不能為類型參數。
不能建立類型參數變量的數組。
不能重載一個方法,該方法的形參都來自于同一個類型參數對象。