9

I'm reading the java source code and I've found things as below:
http://www.java2s.com/Code/JavaAPI/java.util/newTreeSetEComparatorsuperEc.htm

I don't understand why the parameter of this constructor is <? super E>.

As my understanding, it should be <? extend E> instead of <? super E> because if E is comparable, the children of E must be comparable whereas the parents of E may be not.

Martin Schröder
  • 4,176
  • 7
  • 47
  • 81
Yves
  • 11,597
  • 17
  • 83
  • 180

3 Answers3

14

Let's consider three classes: Drink, Juice extends Drink, and OrangeJuice extends Juice.

If I want a TreeSet<Juice>, I need a comparator that will compare any two juices. Of course a Comparator<Juice> will do this.

A Comparator<Drink> will also do this, because it is able to compare any two drinks, and thus any two juices.

A Comparator<OrangeJuice> will not do this. If I wanted to add an AppleJuice to my set of juices, that is not compatible with this comparator as it can only compare orange juices.

Joe C
  • 15,324
  • 8
  • 38
  • 50
7

You create a sorted set of bananas. To do that, you need to be able to compare the bananas. You can thus use a comparator of bananas to do that. But if you have a comparator that can sort any kind of fruit (including bananas), then that'll work too. So you can also use a Comparator<Fruit> or even a Comparator<Food> to sort your bananas.

That's why a Comparator<? super E> is used.

If it was Comparator<? extends E>, you would be able to create a set of bananas with a Comparator<DriedBanana>. But that wouldn't work: a comparator of dried bananas can only compare dried bananas. Not all kinds of bananas.

For more information, also read What is PECS (Producer Extends Consumer Super)?

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
4

it should be instead of because if E is comparable, the children of E must be comparable whereas the parents of E may be not.

Comparator doesn't rely on Comparable objects.
It is even often used as an alternative or a complement.

In fact, this constructor

public TreeSet(Comparator<? super E> comparator) {...}

could have been :

public TreeSet(Comparator<E> comparator) {... }

But by specifying a lower bounded wildcard, JDK developers provided more flexibility for client classes by allowing the Comparator to be interoperable with both current class instances and parent class instances. In some cases, it may make sense.

Now this :

public TreeSet(Comparator<? extend E> comparator) {

cannot be valid as it means that you may finish with a compare() method that specifies subclass type as parameters .
But elements of the Set may contain instances of a specific subclass but not only.

Imagine this code :

TreeSet<CharSequence> set = new TreeSet<>(new Comparator<String>() {

    @Override
    public int compare(String o1, String o2) {
        ...
    }
});

set.add("string");
set.add(new StringBuilder());
...

I want compare Strings but the Set could contain String instances but also any subclass of CharSequence such as StringBuilder, CharBuffer, etc...
And if CharSequence was not abstract, it could also contain instances of them.

With this example, we understand that conceptually Comparator<? extend E> is wrong.

davidxxx
  • 125,838
  • 23
  • 214
  • 215