在Java中,Collections类包含以下方法:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)
它的签名因其对仿制药的高级使用而闻名, 这本书在Nutshell书中的Java中提到过 并在官方Sun Generics Tutorial。
但是,我找不到令人信服的答案:
为什么类型为Collection<? extends T>
的形式参数
比Collection<T>
?还有什么好处?
答案 0 :(得分:6)
类型推断是一个棘手的话题,我承认我不太了解。但是,请查看此示例:
public class ScratchPad {
private static class A implements Comparable<A> {
public int compareTo(A o) { return 0; }
}
private static class B extends A {}
private static class C extends B {}
public static void main(String[] args)
{
Collection<C> coll = null;
B b = Scratchpad.<B>min(coll);
}
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c) {
return null;
}
//public static <T extends Object & Comparable<? super T>> T min(Collection<T> c) {
// return null;
//}
}
考虑min()的第一个签名允许调用编译而第二个签名不允许。这不是一个非常实际的例子,因为我必须问为什么我会明确地将方法输入到<B>
,但是可能存在隐式推断,其中B
将是推断类型。
答案 1 :(得分:5)
?
的一个好处是它禁止向Collection
添加项目
答案 2 :(得分:4)
我认为它实际上并没有为这个方法提供更多的东西,但是当T是类的一部分而不仅仅是静态方法时,它是一个很好的习惯。
他们在这里包含它,所以它可以成为新的约定,其中每个泛型应该扩展?
一类T应遵循PECS:What is PECS (Producer Extends Consumer Super)?
但是静态方法不需要(至少参数,返回值应该总是)
答案 3 :(得分:2)
这是为了支持Java 1.4(以及之前)中方法的遗留签名。
在Java 5之前,这些方法的签名是
public static Object min ( Collection c );
使用多个边界时,擦除规则使第一个绑定方法的原始类型,因此没有Object &
签名将是
public static Comparable min ( Collection c );
并且遗留代码会中断。
这取自O'Reilly的Java Generics and Collections一书,第3.6章
答案 4 :(得分:1)
根据我对马克答案的评论,如果你有像
这样的话class Play {
class A implements Comparable<A> {
@Override
public int compareTo(A o) {
return 0;
}
}
class B extends A {
}
class C extends A {
}
public static <T extends Object & Comparable<? super T>> T min(
Collection<? extends T> c) {
Iterator<? extends T> i = c.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) < 0)
candidate = next;
}
return candidate;
}
public static List<? extends A> getMixedList() {
Play p = new Play();
ArrayList<A> c = new ArrayList<A>();
c.add(p.new C());
c.add(p.new B());
return c;
}
public static void main(String[] args) {
ArrayList<A> c = new ArrayList<A>();
Collection<? extends A> coll = getMixedList();
A a = Play.min(coll);
}
}
更清楚的是min返回A类型的对象(实际签名是<A> A Play.min(Collection<? extends A> c)
)。如果您离开min(Collection<T>)
而没有扩展部分,那么Play.min(coll)
将具有以下签名<? extends A> ? extends A Play.min(Collection<? extends A> c)
,但不是那么明确。