范型类和方法的调用:
泛型程序设计意味着编写的代码可以被很多不同类型的对象所重用。例如,我们不希望为聚集String和File对象分别设计不同的类。实际上根本不需要那么做,因为一个ArrayList类可以聚集任何类型的对象。这是一个泛型程序设计的实例。
1. 简单泛型类的定义:
一个泛型类(generic class)就是具有一个或者多个类型变量的类。 看下面的简单的泛型类Pair例子:
public class Pair<T>
{
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; }
private T first;
private T second;
} Pair类引入一个类型变量T,用尖括号(<>)括起来,并放在类名的后面。泛型类可以有多个类型变量。例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:public class Pair<T,U>{...}
类定义中的类型变量指定方法的返回类型以及域和局部变量的类型,例如:private T first;
注意:类型变量使用大写形式,而且比较短。在Java类库中使用变量E表示集合元素类型,K表示关键字类型,V表示值的类型,T表示任意类型。
- 简单泛型类的实例化:
用具体的类型替换类型参数就可以实例化泛型类型,比如:Pair<String> x = ..
使用泛型类中的构造方法和成员方法是一定要注意类型参数的一致性,比如:
new Pair<T>(T a);
new Pair<String>(String a); //若a的类型和T或者具体的String不一致时需要强制类型转换
泛型方法 :
- 泛型方法的定义
上面已经介绍了如何定义一个泛型类。实际上,还可以定义一个带有类型参数的简单方法。看下面的模板:
public static <T> T getMiddle(T[] b) {
return b[b.length/2];
} 这个方法是用在普通类中定义的,而不是用在泛型类中定义。但是,这是一个泛型方法,这一点可以从尖括号和类型变量中看出来。
需要注意的是,类型变量放在修饰符(这里是public static)的后面,返回类型的前面。当然泛型方法可以定义在普通类中,也可以定义在泛型类中。
2. 泛型方法的调用
当调用一个泛型方法时,在方法名前面的方括号中放入具体类型:
String middle = ArrayAlg.<String>getMiddle(names);
在这种情况下,方法调用中可以省略掉<String>类型参数。编译器有足够的信息来判断出多调用的方法。它用的names的类型(即String[ ]类型)与泛型类型T[ ]进行匹配,并且判断出T一定是String。也就是说以下对于泛型方法的调用的代码也是对的
String middle = ArrayAlg.getMiddle(names);
public class Pair<T>
{
//以下可看作是构造方法
public Pair() { first = null; second = null; }
public Pair(T middle){ this.middle = middle;}
//以下可以看作是泛型类的成员方法
public T getMiddleOne(){return middle;}
//以下两个可以看作是成员变量
private T middle;
public T length; //length要用public或者默认访问修饰符
}
class ArrayAlg
{
public static <T> Pair<T> getMiddle(T[] b)
//这里的泛型方法返回类型为Pair<String>
{
return new Pair<T>(b[b.length / 2]);
//b[b.length / 2]是T[]类型,所以无需强制类型转换。
}
}
定义泛型方法时,必须在返回值前边加一个<T>,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。
Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。
Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。为什么要用变量c来创建对象呢?既然是泛型方法,就代表着我们不知道具体的类型是什么,也不知道构造方法如何,因此没有办法去new一个对象,但可以利用变量c的newInstance方法去创建对象,也就是利用反射创建对象。泛型方法要求的参数是Class<T>类型,而Class.forName()方法的返回值也是Class<T>,因此可以用Class.forName()作为参数。其中,forName()方法中的参数是何种类型,返回的Class<T>就是何种类型。在本例中,forName()方法中传入的是User类的完整路径,因此返回的是Class<User>类型的对象,因此调用泛型方法时,变量c的类型就是Class<User>,因此泛型方法中的泛型T就被指明为User,因此变量obj的类型为User。当然,泛型方法不是仅仅可以有一个参数Class<T>,可以根据需要添加其他参数。为什么要使用泛型方法呢?因为泛型类要在实例化的时候就指明类型,如果想换一种类型,不得不重新new一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活。