日期:2014-05-20 浏览次数:20601 次
?本篇文章是第7版Core Java2第13章的读书笔记。
?
所谓泛型从直观上看就是含有<T>这样的表示,T是包括自定义类在内的所有从Object继承的类(因此,int,double等基本数据类型不能使用泛型)。使用泛型典型的例子即是容器类,比如ArrayList<E>,Map<K,V>等。
?
Java引入泛型带来的一个最显而易见的好处是代码的重用,因为我们编写一次的代码可以被很多不同类型的对象所重用。可以举一个简单的例子:我们有一个类(或方法)实现的是两个数的相加,当没有引入泛型的时候我们需要为int,double不同的类型写不同的实现,然后在有了泛型之后我们只需一个实现,在调用时传入不同类型的数(当然应该是Integer或者Double而不是int或double,原因如前所述)即可,简单代码如下: 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;
}
}
}
在这个例子中我们计算了数组中的最小元素,但是我们如何知道类型T有compareTo方法呢。因此,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,在静态域和静态方法中也不能使用泛型
?