了解在Java集合类中使用泛型

时间:2015-09-17 14:02:32

标签: java generics collections types

在研究Java的Collection类(OpenJDK 8_update40)之后,我发现了以下方法:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
    Iterator<? extends T> i = coll.iterator();
     T candidate = i.next();

     while (i.hasNext()) {
         T next = i.next();
         if (next.compareTo(candidate) > 0)
             candidate = next;
     }
     return candidate;
}

我不完全理解这里使用泛型类型。据我所知,T是Object的子类型,它也必须实现Comparable接口,该接口也通过泛型参数进行参数化。 Comparable状态的参数必须是T的某种超类型。由于我们有某种递归类型定义。

但这是我的问题:据我所知,Java中的每个类型都是Object的子类型,那么他们为什么要指定 它在T?

的定义范围内

3 个答案:

答案 0 :(得分:6)

这是出于向后兼容的原因。

使用泛型类型时,此泛型类型具有下限,例如:

<T extends Foo & Bar> void someMethod(T xxx)

然后someMethod的运行时签名将是:

void someMethod(Foo xxx)

(好吧,好的,参数名称不存在,但是你得到了图片)。

现在,Collections.max()在 JDK 5之前定义了;它的签名是:

public static Object max(Collection coll)

,在Java 5中,可以翻译为:

public static Object max(Collection<Object> coll)

问题是max的返回值不能是Comparable ......

当然,在这种情况下,会增加更多困难:

  • 第二个下限将本身设为泛型;
  • 此外Comparable是PECS方式的“消费者”(因此Comparable<? super T>);
  • 作为参数传递的Collection可以是T或任何扩展T的任何类型,因此? extends T;我们不关心实际类型,只保证Collection保证返回至少 T的内容。

这解释了有点复杂的签名......

答案 1 :(得分:0)

因为如果你不使用&#34; T&#34;该集合只接受Object的实例。

例如,String是Object的子类型,但不会编译,因为集合只接受Object实例。

答案 2 :(得分:0)

这是由于covariance vs. contravariance

作为一般规则:

  • 如果使用泛型类型T返回值,则在Iterator中使用<? extends T>
  • 如果使用泛型类型T接受值,则可以使用{\ n}中的<? super T>