日期:2014-05-20  浏览次数:20601 次

J2SE泛型1

?本篇文章是第7版Core Java2第13章的读书笔记。

?

所谓泛型从直观上看就是含有<T>这样的表示,T是包括自定义类在内的所有从Object继承的类(因此,intdouble等基本数据类型不能使用泛型)。使用泛型典型的例子即是容器类,比如ArrayList<E>,Map<K,V>等。

?

Java引入泛型带来的一个最显而易见的好处是代码的重用,因为我们编写一次的代码可以被很多不同类型的对象所重用。可以举一个简单的例子:我们有一个类(或方法)实现的是两个数的相加,当没有引入泛型的时候我们需要为intdouble不同的类型写不同的实现,然后在有了泛型之后我们只需一个实现,在调用时传入不同类型的数(当然应该是Integer或者Double而不是intdouble,原因如前所述)即可,简单代码如下:

public class Add<T>{

?????? private T first;

?????? private T second;

?????? public Add(T first,T second){

?????? this.first=first;

?????? this.second=second;

}

public <T> T result(){

?????? return first+second;

}

}

这样我们调用Add<Integer> mm=new Add<Integer>(5,3)mm.result();或者Add<Double> mm=new Add<Double>(5.0,3.0)mm.result()就可以了。

?

?

泛型方法

关于泛型方法,在前面我们已经看到了一个例子(public <T> T result()),其基本语法是将类型变量即<T>放在修饰符(这里是public)的后面,返回类型(这里是T)的前面。

?

类型变量的限定

一个简单的例子:

Class ArrayAlg{

?????? public static <T> T min(T[] a){

?????? if(a==null||a.length==0) return null;

?????? T smallest=a[10];

?????? for(int i=1;i<a.length;i++){

?????? if(smallest.compareTo(a[i])>0) smallest=a[i];

return smallest;

}

}

}

在这个例子中我们计算了数组中的最小元素,但是我们如何知道类型TcompareTo方法呢。因此,T的类型就限制为实现了Comparable接口的类。可以通过对T设定限制来做到这一点:

public static <T extends Comparable> T min(T[] a)

需要注意的是这里使用的关键字是extends而不是implements,因为这里表示的是T是绑定类型的子类型,extends更接近子类型的概念。当有多个限定的时候可以使用‘&’符号,如下:

T extends Comparable&Serializable

因为Java是一种单继承的语言,所以在限定中最多只能有一个类,并且必须是界限列表中的第一个,但是可以有多个接口类型。

?

泛型的原理

实际上,java虚拟机并没有泛型类型对象,也就是说所有的对象都属于某一个特定的普通类。那么泛型类是如何实现的呢?

在我们定义一个泛型类型时,编译器会自动提供一个相应的原始类型(raw type),擦除类型变量,并用限定的原始类型(无限定的用Object)替换。Add<T>的原始类型如下:

public class Add{

?????? private Object first;

?????? private Object second;

?????? public Add(Object first, Object second){

?????? this.first=first;

?????? this.second=second;

}

public Object result(){

?????? return first+second;

}

}

当有多个限定类型时,使用第一个边界的类型变量来替换。

在替换之后,我们调用result()方法时,返回的是Object类型,但是编译器会自动进行强制类型转换,将其转化为我们需要的类型。

以上可以被概括为下面三句话:

1,? 虚拟机中没有泛型,只有普通的类和方法。

2,? 所有的类型参数都用它们的边界替换。

3,? 为保持类型安全性,必要时会自动插入强制类型转换。

?

泛型的类型

我们考虑下面一段伪代码: Pair<String> stringPair=......; Pair<Employee> employeePair=......; if(stringPair.getClass()==employeePair.getClass())


?这条if语句的结果是什么呢?实际上,在类型比较的时候<T>会被忽略,可以看到的只是类Pair。因此,比较的结果是true。同样,if(stringPair instanceof Pair<T>)也是真。

我们需要注意的是,无论何时使用instanceof或者涉及泛型类型的强制类型转换表达式编译器都会产生一个警告。

?

泛型的限制

1,泛型不能应用于数组

2,泛型类型不能实例化,也就是说我们不能对泛型类型使用new表达式

3,在静态域和静态方法中也不能使用泛型

?