泛型方法

泛型方法可以定义在泛型类中,也可以定义在普通类中。定义泛型方法时,将泛型变量用尖括号包裹,并且将泛型变量置于方法修饰符和方法返回值之间。

public class ArrayAlg{
    public static <T> T getMiddle(T... a){
        return a[a.length / 2];
    }
}

当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型,实例化类型参数:

String middle = ArrayAlg.<String>getMiddle("Hello","World","!");

在大多数情况下,调用泛型方法可以省略对类型参数,编译器有足够的信息能够推断出如何实例化类型参数,下面的代码与上面的代码具有相同的效果:

String middle = ArrayAlg.getMiddle("Hello","World","!");

编译器根据传入方法的参数(“Hello”、“World”、”!“)推断出应该使用String实例化类型参数T。

在少部分特殊的情况下,编译器无法推断出如何实例化类型参数,比如下面的代码:

double middle = ArrayAlg.getMiddle(1.01,2.02,3);

解释这句代码有两种方法,且两种方法都是合法的。简单的说,编译器会自动将1.01和2.02打包成Double对象,将3打包成Integer对象,因为不能确定到底是使用Double还是Integer实例化类型参数T,编译器将尝试寻找Double和Integer的共同父类。事实上,将会找到两个共同父类——Number和Comparable接口,其本生也是一个泛型类型。最终,编译器无法判断到底使用什么类型实例化类型参数,因此报错。在这种情况下,可采取的补救措施时将所有参数写成double值。