正如前面的示例所示,泛型类中的方法可以使用类的类型形参,因此能够自动的成为与类型形参相关的泛型方法.但是,也可以声明使用一个或多个自己的类型形参的泛型方法.而且,可以创建不包含在泛型类的泛型方法.
下面的程序声明一个静态泛型方法arraysEqual(),该方法判断两个数组是否以相同的顺序包含相同的值.他可以用来比较任意两个数组,只要数组的类型相同或兼容即可.
public class test2 { static<T extends Comparable<T>,V extends T> boolean arraysEqual(T[] x,V[] y) { if(x.length != y.length) return false; for(int i=0;i<x.length;i++) if(!x[i].equals(y[i])) return false; return true; } // @param args public static void main(String args[]) { Integer nums[] = {1,2,3,4,5}; Integer nums2[] = {1,2,3,4,5}; Integer nums3[] = {1,2,4,5,6}; Integer nums4[] = {1,2,323,44,5,6}; if(arraysEqual(nums,nums)) System.out.println("nums equals nums"); if(arraysEqual(nums,nums2)) System.out.println("nums equals nums2"); if(arraysEqual(nums,nums3)) System.out.println("nums equals nums3"); if(arraysEqual(nums,nums4)) System.out.println("nums equals nums4"); } }
程序输出如下所示:
nums equals nums nums equals nums2
下面仔细分析arraysEqual()方法,首先,注意声明该方法的语句:
static<T extends Comparable<T>,V extends T> boolean arraysEqual(T[] x,V[] y)
类型形参在方法的返回类型之前声明.其次,注意类型T扩展了Comparable<T>.Comparalbe是在java.lang中声明的一个接口.实现Comparable的类定义了可以调用的对象.因此,需要comparable的上层约束来确保arraysEqual()只能由可以相互比较的对象使用.Comparable是泛型的,且他的类型形参指定了他所比较的对象的类型.接下来注意类型V是类型T的上层约束.因此,V必须与T的类型相同或是其子类,这种关系使得arratsEqual()只能使用彼此相互比较的实参调用.还要注意arraysEqual()是静态方法,这使得他可以独立于任何对象调用.但是泛型方法既可以是静态的,也可以是非静态的,对此没有严格的限制.
现在注意arraysEqual()是如何在main()中被调用的:使用了正常的调用语法,而不必指定类型实参.这是因为实参的类型可以被自动识别,T和V的类型会相应的进行调整.例如,在第一个调用中:
if(arrayEqual(nums,nums))
第一个实参的基类是Integer,导致使用Integer取代了T.第二个实参的基类型也是Integer,也用Integer取代了V,因此,对arraysEqual()的调用是合法的,两个数组可以进行比较.
现在注意注释掉的代码,如下所示:
//if(arrayEqual(nums,dvals))
如果删除注释并尝试编译程序,将会出现错误,原因是类型形参V由T约束(V extends T).这意味着V必须与T的类型相同或是其子类.在本例中,第一个实参的类型是Integer,使得T的类型为Integer,但是第二个实参的类型为Double,他不是Integer的子类.这使得arraysEqual()的调用非法,并导致编译时的类型不匹配错误.
对用来创建arrayEqual()的语法进行推广,可以得到如下所示的泛型方法的语法:
<type-param-list> ret-type meth-name(param-list)
其中,type-param-list是由逗号风格的类型形参列表,注意,对于泛型方法,类型形参列表位于返回类型之前.