前面已经介绍了如何定义一个泛型类。实际上,还可以定义一个带有类型参数的简单方法。
class ArrayAlg {
public static <T> T getMiddle(T... a) {
return a[a.length / 2];
}
}
这个方法是在普通类中定义的,而不是在泛型类中定义的。然而,这是一个泛型方法, 可以从尖括号和类型变量看出这一点。注意,类型变量放在修饰符(这里是public static)的后面,返回类型的前面。
泛型方法可以定义在普通类中,也可以定义在泛型类中。
当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型:
String niddle = ArrayAlg.<String>getmiddle(“John”,“Q”,"Public");
在这种情况(实际也是大多数情况)下,方法调用中可以省略<String>类型参数。编译器有足够的信息能够推断出所调用的方法。它用names的类型(即String[])与泛型类型T[] 进行匹配并推断出T 一定是String。也就是说,可以调用
String middle = ArrayAlg.getMiddle("John", "Q”, "Public");
几乎在大多数情况下,对于泛型方法的类型引用没有问题。偶尔,编译器也会提示错误,此时需要解译错误报告。看一看下面这个示例:
double middle = ArrayAlg.getMiddle(3.14f 1729, 0);
错误消息会以晦涩的方式指出(不同的编译器给出的错误消息可能有所不同):解释这句代码有两种方法,而且这两种方法都是合法的。简单地说,编译器将会自动打包参数为1个 Double和2个Integer对象,而后寻找这些类的共同超类型。事实上,找到2个这样的超类型: Number和Comparable接口,其本身也是一个泛型类型。在这种情况下,可以采取的补救措施是将所有的参数写为double值。
类型变量的限定
有时,类或方法需要对类型变量加以约束。下面是一个典型的例子我们要计算数组中的最小元索:
class ArrayAlg
{
public static <T> T min(T[] a) // almost correct
{
if (a = null || a.length == 0) return null;
T smallest = a[0];
for (int i = 1; i < a.length; i++)
if (s(nallest.coinpareTo(a[i]) > 0) smallest = a[i];
return smallest;
}
}
但是,这里有一个问题。请看一下min方法的代码内部。变量smallest类型为T,这意味着它可以是任何一个类的对象。怎么才能确信T所属的类有compareTo方法呢?
解决这个问题的方案是将T限制为实现了Comparable接口(只含一个方法compareTo的 标准接口)的类。可以通过对类型变量T设置限定(bound)实现这一点:
public static <T extends Coiparable> T min(T[] a)...
实际上Comparable接口本身就是一个泛型类。目前,我们忽略其复杂性以及编泽器产 生的警告。
现在,泛型的min方法只能被实现了 Comparable接口的类(如String、Date等)的数组调用。由于Rectangle炎没有实现Comparable接口,所以凋用min将会产生 一个编译错误。
—个类型变量或通配符可以存多个限定,例如:
T extends Comparable & Serializable
限定类型用&分隔,而逗号用来分隔类型变最。
在Java的继承中,可以根据需要拥有多个接口超类型,但限定中至多有一个类。如果用一个类作为限定,它必须是限定列表中的第一个。
在程序清单中,编写了一个泛型方法mimnax。这个方法计算泛型数组的最大值和最小值,并返回Pair<T>。
程序清单:
pair.java文件:
package pair2; /** * Created by IBM on 2017/10/16. */ /** * @version 1.00 2004-05-10 * @author Cay Horstmann */ 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; }PairTest1.java文件
package pair2; import java.util.Calendar; import java.util.GregorianCalendar; /** * Created by IBM on 2017/10/16. * 泛型类型 */ public class PairTest1 { public static void main(String[] args) { GregorianCalendar[]birthdays={ new GregorianCalendar(1906, Calendar.DECEMBER,9),//G,Hopper new GregorianCalendar(1815, Calendar.DECEMBER,10),//A,Lovelace new GregorianCalendar(1903, Calendar.DECEMBER,3),//J,von Neumann new GregorianCalendar(1910, Calendar.JULY,22)//K,Zuse }; Pair<GregorianCalendar>mm=ArrayAlg.<GregorianCalendar>minmax(birthdays); System.out.println("min = "+mm.getFirst().getTime()); System.out.println("max = "+mm.getSecond().getTime()); } } class ArrayAlg{ public static<T extends Comparable> Pair<T> minmax(T[] a){ if (a == null || a.length == 0) return null; T min=a[0]; T max=a[0]; for (int i=0;i<a.length;i++){ if(min.compareTo(a[i])>0)min=a[i]; if(max.compareTo(a[i])<0)max=a[i]; } return new Pair<>(min,max); } }
运行结果: