通用方法

通用类型参数通常在类或接口级别定义,但方法和(很少) 构造函数也支持声明绑定到单个方法调用范围的类型参数。

class Utility // no generics at the class level
{
    @SafeVarargs
    public static <T> T randomOf(T first, T... rest) {
        int choice = new java.util.Random().nextInt(rest.length + 1);
        return choice == rest.length ? first : rest[choice];
    }

    public static <T extends Comparable<T>> T max(T t1, T t2) {
        return t1.compareTo(t2) < 0 ? t2 : t1;
    }
}

请注意,类型参数声明 T<T extends Comparable<T>> 分别出现在方法修饰符之后和返回类型之前。这允许类型参数 T 在这些方法的范围内使用,其作用如下:

  • 参数类型
  • 返回类型
  • 局部变量类型

虽然上述两种方法都使用相同的类型参数名称 T,但在方法级别它们完全相互独立。编译器将根据在调用该方法的每个调用站点处传递给该方法的参数来推断实际类型。由于 max 方法声明了 T extends Comparable<T>,编译器还强制推断类型是 Comparable 接口的兼容实现。 **

Integer num1 = 1;
Integer num2 = 2;
String str1 = "abc";
String str2 = "xyz";

Integer bigger = Utility.max(num1, num2);
assert bigger == num2;

String later = Utility.max(str2, str1);
assert later == str2;

Utility.max(num1, str1); // compiler error: num1 and str1 are incompatible types

Utility.max(new Object(), new Object()); // compiler error: Object does not implement Comparable

Java 8 显着提高了编译器在呼叫站点正确推断泛型类型的能力。如果编译器无法推断出正确的类型,开发人员可以明确地将类型声明为调用的一部分:

Object obj = Utility.<Object>randomOf(str1, new Object(), num1);