13

I understand in

Comparator < ? super T> comp

it returns the maximum element of the given collection, according to the order defined by the specified comparator. But I don't understand the purpose of the

super T

Could anyone possibly explain?

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Marcello
  • 423
  • 1
  • 5
  • 12

4 Answers4

20

The term ? super T means "unknown type that is, or is a super class of, T", which in generics parlance means its lower bound is T.

This signature is used because T may be assigned to, and compared with, any variable whose type is, or is a super class of, T. Ie if a Comparator can accept a super class of T in its compare() method, you can pass in a T.

This follows the PECS mnemonic: "Producer Extends, Consumer Super", which means that producers of things should work with things that have an upper bound ( ? extends T) and consumers (like comparator implementations that use things) should work with lower bounds ( ? super T).

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Bohemian
  • 412,405
  • 93
  • 575
  • 722
7

In here < ? super T> means generics - NOT comparisons.

It means you have a Comparator with a generic type of ? super T (something that extends is super typed by T), as explained in this thread

comp is the variable name (binding).

So basically in here Comparator < ? super T> is a type and comp is an identifier (variable name), that is of type Comparator <? super T>


For more info: Java Generics

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
amit
  • 175,853
  • 27
  • 231
  • 333
0

Lets take an example

interface Fruit {
    int getPrice();
}

class Orange implements Fruit {
    int price;

    public Orange(int price) {
        this.price = price;
    }

    @Override
    public int getPrice() {
        return price;
    }
}

interface Apple extends Fruit {
    int getAppleQuality();
}

class WineSapApple implements Apple {

    public int price, quality;
    public WineSapApple(int price, int quality) {
        this.price = price;
        this.quality = quality;
    }
    @Override
    public int getPrice() {
        return price;
    }
    @Override
    public int getAppleQuality() {
        return quality;
    }
}

class AppleQualityComparator implements Comparator<Apple> {
    public int compare(Apple a1, Apple a2) {
        return Integer.compare(a1.getAppleQuality(), a2.getAppleQuality());
    }
}

class FruitPriceComparator implements Comparator<Fruit> {
    public int compare(Fruit f1, Fruit f2) {
        return Integer.compare(f1.getPrice(), f2.getPrice());
    }
}

Okay now

        List<Fruit> fruits = List.of(new WineSapApple(100, 50), new Orange(10));
        Collections.sort(fruits, new FruitPriceComparator());
//        Collections.sort(fruits, new AppleQualityComparator()); compilation error

Importantly we want to re use the Comparator declared at super class level

    List<Apple> apples = List.of(new WineSapApple(100, 50), new WineSapApple(150, 75));
    Collections.sort(apples, new FruitPriceComparator()); //<--- reason for `? super T`
    Collections.sort(apples, new AppleQualityComparator());
Kanagavelu Sugumar
  • 18,766
  • 20
  • 94
  • 101
-1

Let's use the type of one of TreeSet's constructors as an example:

TreeSet(Comparator<? super E> comparator)

Imagine that E is a String, so we mentally specialize the constructor:

TreeSet(Comparator<? super String> comparator)

I can instantiate TreeSet like this:

var mySet = new TreeSet<String>(myStringComparator);

Here, myStringComparator might look like this.

Comparator<String> myStringComparator = new Comparator<>() {
    @Override
    public int compare(String o1, String o2) {
        return 0;
    }
};

The <? super String> part of TreeSet(Comparator<? super String> comparator) allows us to also provide the constructor with a comparator that compares super types of Strings. That's a more general, less-specific, comparator you might say.

For example, CharSequence is a super type of String, that's why this works, too:

Comparator<CharSequence> myCharSeqComparator = new Comparator<>() {
    @Override
    public int compare(CharSequence o1, CharSequence o2) {
        return 0;
    }
};

var mySet2 = new TreeSet<String>(myCharSeqComparator);

Hypothetically, if TreeSet's constructor were defined like this:

TreeSet(Comparator<E> comparator)

which in our example specializes to

TreeSet(Comparator<String> comparator)

we could only provide Comparator<String>, but not Comparator<CharSequence> or Comparator<Object>.

This would be a pity since we might want to use the more general comparators that don't need the specifics of String to be able to compare.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171