泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,泛型就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),
然后在使用/调用时传入具体的类型(类型实参)。
1.为什么要使用泛型程序设计泛型程序设计(Generic programming)意味着编写的代码可以被很多不同类型的对象所重用。
在Java增加泛型类之前已经有一个ArrayList类。
在Java中增加泛型类之前,泛型程序设计使用继承实现的。ArrayLst类只维护一个Object引用的数:
public class ArrayList //before generic class
{
private Obejct[] elementData;
...
public Objetc get(int i){...}
public void add(Obejct o){...}
}
这个方法有两个问题,当获取一个值时必须进行强制类型转换。
ArrayList files=new ArrayList(); ... String filename=(String)files.get(0);
此外,这里没有错误检查。可以向数组列表中添加任何类的对象。
泛型提供了一个更好的解决方案:类型参数(type parameter)。ArrayList类有一个类型参数用来指示元素的类型:
ArrayListfiles=new ArrayList<>();
这使得代码具有更好的可读性,人们一看就知道这个数组列表中包含的String对象。
2.定义简单泛型类一个泛型类就是具有一个或者多个类型变量的类。例如:
public class Pair{ private T first; private T second; public Pair(){ first=null; second=null; } public Pair(T first,T second){ this.first=first; this.second=second; } public T getFirst(){ return first; } public T getSecond(){ return second; } public void setFirst(T newValue){ first=newValue; } public void setSecond(T newValue){ second=newValue; } }
Pair类引入了一个类型变量T,用尖括号(<>)括起来,并放在类名的后面。泛型类可以有多个类型变量。例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:
public class Pair{...}
类定义中的类型变量指定方法的返回类型以及域和局部变量的类型。
3.泛型方法除了定义泛型类,还可以定义泛型方法。
class ArrayAlg{
public static T getMiddle(T... a){
return a[a.lenth/2]
}
}
这个方法在普通类中定义,而不是在泛型类中。但这是一个泛型方法,可以从尖括和类型变量看出这一点。注意,类型变量放在修饰符(这里是public static)的后面,返回类型的前面。
泛型方法可以定义在普通类中,也可以定义在泛型类中。
当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型:
String middle=ArrayAlg.getMiddle("John","Q.","public");
这种情况下(实际上也是大多数情况),方法调用中可以省略类型参数。编译器用names的类型(String[])与泛型T[]进行匹配并推断出T一定是String。即可以调用
String middle=ArrayAlg.getMiddle("John","Q.","Public");
4.类型变量的限定
有时,类或方法需要对类型变量加以约束。下面计算数组中的最小元素。
class ArrayAlg{
public static min(T[] a){ //almost correct
if(a==null||a.length==0){
return null;
}
T smallest=a[0];
for(int i=1;i0)){
smallest=a[i];
}
}
return smallest;
}
}
这里的问题在于,变量smallest类型为T,意味着它 可以是任何一个类的对象。解决这个问题的方案是将T限制为了实现Comparable接口(只含一个方法compareTo的标准接口)的类。可以通过对类型变量T设置限定(bound)实现这一点:
public staticT min(T[] a) ...
实际上Comparable接口本身就是一个泛型类型。目前,我们忽略其复杂性以及编译器产生的警告。
现在,泛型的min方法只能被实现了Comparable接口的类(如String、LocalDate等)的数组调用。由Rectangle类没有实Comparable接口,所以调用min将会产生一个编译错误。
表示T应该是绑定类型的子类型(subtype)。T和绑定类型可以是类,也可以是接口。选择关键字extends的原因是更接近子类的概念,并且Java的设计者也不打算在语言中再添加一个新的关键字
一个类型变量或通配符可以有多个限定,例如:
T extends Comparable & Serializable
限定类型用“&”分隔,而逗号用来分隔类型变量。
5.泛型代码和虚拟机 6.约束与局限性 7.泛型类型的继承规则 8.通配符类型 9.反射和泛型


