天天看點

java泛型

 泛型的構成

由泛型的構成引出了一個類型變量的概念。根據Java語言規範,類型變量是一種沒有限制的标志符,産生于以下幾種情況:

泛型類聲明

泛型接口聲明

泛型方法聲明

泛型構造器(constructor)聲明

如果一個類或接口上有一個或多個類型變量,那它就是泛型。類型變量由尖括号界定,放在類或接口名的後面:

<code>1</code>

<code>public</code> <code>interface</code> <code>List&lt;T&gt;</code><code>extends</code> <code>Collection&lt;T&gt; {</code>

<code>2</code>

<code>...</code>

<code>3</code>

<code>}</code>

簡單的說,類型變量扮演的角色就如同一個參數,它提供給編譯器用來類型檢查的資訊。

非常的相似,如果方法和構造器上聲明了一個或多個類型變量,它們也可以泛型化。

<code>public</code> <code>static</code> <code>&lt;t&gt; T getFirst(List&lt;T&gt; list)</code>

這個方法将會接受一個List&lt;T&gt;類型的參數,傳回一個T類型的對象。

通配符

在本文的前面的部分裡已經說過了泛型類型的子類型的不相關性。但有些時候,我們希望能夠像使用普通類型那樣使用泛型類型:

向上造型一個泛型對象的引用

向下造型一個泛型對象的引用

例如,假設我們有很多箱子,每個箱子裡都裝有不同的水果,我們需要找到一種方法能夠通用的處理任何一箱水果。更通俗的說法,A是B的子類型,我們需要找到一種方法能夠将C&lt;A&gt;類型的執行個體賦給一個C&lt;B&gt;類型的聲明。

為了完成這種操作,我們需要使用帶有通配符的擴充聲明,就像下面的例子裡那樣:

<code>List&lt;Apple&gt; apples =</code><code>new</code> <code>ArrayList&lt;Apple&gt;();</code>

<code>List&lt;?</code><code>extends</code> <code>Fruit&gt; fruits = apples;</code>

“? extends”是泛型類型的子類型相關性成為現實:Apple是Fruit的子類型,List&lt;Apple&gt; 是 List&lt;? extends Fruit&gt; 的子類型。

? super

使用 ? super 通配符一般是什麼情況?讓我們先看看這個:

<code>List&lt;Fruit&gt; fruits =</code><code>new</code> <code>ArrayList&lt;Fruit&gt;();</code>

<code>List&lt;?</code><code>super</code> <code>Apple&gt; = fruits;</code>

我們看到fruits指向的是一個裝有Apple的某種超類(supertype)的List。同樣的,我們不知道究竟是什麼超類,但我們知道Apple和任何Apple的子類都跟它的類型相容。既然這個未知的類型即是Apple,也是GreenApple的超類,我們就可以寫入:

<code>fruits.add(</code><code>new</code> <code>Apple());</code>

<code>fruits.add(</code><code>new</code> <code>GreenApple());</code>

如果我們想往裡面加入Apple的超類,編譯器就會警告你:

<code>fruits.add(</code><code>new</code> <code>Fruit());</code>

<code>fruits.add(</code><code>new</code> <code>Object());</code>

因為我們不知道它是怎樣的超類,所有這樣的執行個體就不允許加入。

從這種形式的類型裡擷取資料又是怎麼樣的呢?結果表明,你隻能取出Object執行個體:因為我們不知道超類究竟是什麼,編譯器唯一能保證的隻是它是個Object,因為Object是任何Java類型的超類。