问题
In Java, the Collections class contains the following method:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> c)
Its signature is well-known for its advanced use of generics, so much that it is mentioned in the Java in a Nutshell book and in the official Sun Generics Tutorial.
However, I could not find a convincing answer to the following question:
Why is the formal parameter of type Collection<? extends T>
, rather
than Collection<T>
? What's the added benefit?
回答1:
One benefit of the ?
is that it prohibits additions of items to the Collection
回答2:
Type inference is a tricky topic that I'll admit that I don't know that much about. However, examine this example:
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;
//}
}
Consider that the first signature of min() allows the call to compile whereas the second does not. This isn't a very practical example, since one must ask why I would be explicitly typing the method to <B>
, but perhaps there is an implicit inference where B
would be the inferred type.
回答3:
I think it actually doesn't give you anything more for this method, however its a good habit to get into when T is part of the class and not just a static method.
They are including it here so it can become the new convention where every generic should be extended by ?
A class of T should follow PECS: What is PECS (Producer Extends Consumer Super)?
But a static method doesn't need to (at least the parameters, the return value should always)
回答4:
This is to support a legacy signature of the method in Java 1.4 ( and before ).
Prior to Java 5 the signature for these methods was
public static Object min ( Collection c );
With multiple bounds the erasure rules make the first bound the raw type of the method, so without Object &
the signature would be
public static Comparable min ( Collection c );
and legacy code would break.
This is taken from O'Reilly's Java Generics and Collections book, chapter 3.6
回答5:
Building on the comments I put on Mark's answer, if you have something like
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);
}
}
It's clearer that min returns an object of type A (the actual signature is <A> A Play.min(Collection<? extends A> c)
). If you leave min(Collection<T>)
without the extends part then Play.min(coll)
will have the following signature <? extends A> ? extends A Play.min(Collection<? extends A> c)
which isn't as clear.
来源:https://stackoverflow.com/questions/2907297/signature-of-collections-min-max-method