3

What are the differences between the following three signatures?

static <T> void foo(List<T>,           Comparator<? super T>);
static <T> void bar(List<? extends T>, Comparator<T>        );
static <T> void baz(List<? extends T>, Comparator<? super T>);

I know what extends and super mean in Generics. My question is whether there is a difference between foo, bar and baz. Should I make one of the parameters invariant and the other one variant in the appropriate direction, or should I make both of them variant? Does it make a difference?

Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246
fredoverflow
  • 256,549
  • 94
  • 388
  • 662

3 Answers3

5

PECS - Producer extends, consumer super.

To explain this "rule":

  • extends means the genericized object produces elements of the type. When it's a collection, it means you can only take elements from the collection, but not put them in. The comparator
  • super means the object consumes objects of the selected type. So you can add to the collection, but not read from it.
  • the lack of extends and super means you can do both for the exact type specified.

Regarding the Comparator, I don't think it makes any difference. Normally, it would be <? super T> because you the comparator consumes objects, but in all three cases you can safely invoke Collections.sort(list, comparator); (the signature of which is <? super T>)

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • I know what `extends` and `super` mean in Generics. My question is whether there is a difference between `foo`, `bar` and `baz`. Should I make one of the parameters invariant and the other one variant in the appropriate direction, or should I make both of them variant? Does it make a difference? – fredoverflow Mar 17 '12 at 22:50
  • 1
    it all depends on what happens in the method body. – Bozho Mar 17 '12 at 23:01
  • Basically, the method body will probably refer to the type `T`, so the implementation of `foo` and `bar` will have to look different because they use a different `T`. – Louis Wasserman Mar 18 '12 at 12:49
2

The only difference is whether T represents the type parameter of the List, the Comparator, or something in between.

As far as the caller is concerned, the three method signatures are equivalent, i.e. whenever one of them can be used, the others can be used as well.

For the method implementation foo is probably most convenient, as it allows modifying the list without needing an additional capture conversion, which would require delegating to a helper method.

meriton
  • 68,356
  • 14
  • 108
  • 175
1

I believe that ? extends T means that the List may be generic of any type that is derived from T, whereas List<T> can only be a List of T and not any of its derived classes.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
Puppy
  • 144,682
  • 38
  • 256
  • 465
  • I know what `extends` and `super` mean in Generics. My question is whether there is a difference between `foo`, `bar` and `baz`. Should I make one of the parameters invariant and the other one variant in the appropriate direction, or should I make both of them variant? Does it make a difference? – fredoverflow Mar 17 '12 at 22:50