Collections.min / max方法的签名

时间:2010-05-25 18:14:23

标签: java generics wildcard

在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>?还有什么好处?

5 个答案:

答案 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),但不是那么明确。