下面是一个非常典型的泛型方法声明:
public static <T> int max(List<T> list, Comparator<? super T> c) {
:
:
}
有两种泛型声明:1) 泛型类/接口,和 2) 泛型方法。一旦你对这两个习语感到满意,你就可以很好地理解泛型了。原始类型声明是:
public static int max(List list, Comparator c) {
:
:
}
原始类型声明很容易看出这个方法返回一个 int 类型的调用者的值。该方法接受两个参数:一个 List 实例和一个 Comparator 实例。
原始类型声明的问题在于它不安全。为什么?因为List<E>
和Comparator<T>
都是使用正式的泛型类型参数定义的泛型类。如果您使用泛型类,但没有指定它的参数(如上面的声明),您将失去泛型为您提供的所有类型安全性和表达能力。
通用方法的特征在于以下方法:
public <T> MyType myMethodName( /* parameters */) { ... }
请注意,泛型方法是在方法声明中使用其类型参数声明的,并且类型参数紧接在返回类型之前。这是标准的。
在这种情况下<T>
,表示您的方法的无界类型参数。无论 T 出现在您的方法中的何处,传递给您的方法的实际类型参数都将代替 T。使方法参数依赖于 T 是常见的但不是必需的(但 T 可以出现在方法主体内的任何位置可以出现类型声明——类型擦除需要一些例外)。
在您的示例中,参数列表是...
(List<T> list, Comparator<? super T> c)
第一个参数指定list
传递给您的方法的实例将具有 List 类型。因为 T 是您的方法声明中列出的泛型方法类型参数,您可以想象它替换了传递给您的方法的实际类型参数,例如。List<String> list.
第二个参数有点复杂。它是有界通配符类型参数。语义?
是“任何类型”,语义super
是“任何属于同一类或超类的类”。因此,第二个参数读取为“与传递给您的方法的实际类型参数 T 相同类型或超类型的任何类型”。
有一个适合有界通配符类型的助记符:PECS。生产者扩展,消费者超级。比较器始终是其实例的消费者,因此在参数列表中指定它们的正确方法如您的方法声明中所示。