天天看点

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类型的超类。