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?
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?
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).
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
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());
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.