Explanation of Generic <T Extends Comparable<? Super T>> in Collection.Sort/ Comparable Code

Explanation of generic T extends Comparable? super T in collection.sort/ comparable code?

Actually, it means that T can implement Comparable<? super T>, not just Comparable<T>.

For example, it means that a Student class can implement Comparable<Person>, where Student is a subclass of Person:

public class Person {}

public class Student extends Person implements Comparable<Person> {
@Override public int compareTo(Person that) {
// ...
}
}

In this case, a List can be sorted by Collections.sort() but only based on Person's properties, because you pass the Student instance into compareTo() as a Person (unless you downcast it, of course).

In practice however, you'll never see a Student class implement Comparable<Person>. That's because Person will probably have implemented Comparable<Person>, and Student inherits it implementation. The end result is the same however: you can pass a List<Student> to Collections.sort() and have it sorted on Person's properties.

The difference between Comparable<T> and Comparable<? super T> is more obvious in the overloaded version of Collections.sort() that takes a Comparator<? super T>:

class ByAgeAscending implements Comparator<Person> {
@Override public int compare(Person a, Person b) {
return a.getAge() < b.getAge();
}
}

List<Student> students = getSomeStudents();
Collections.sort(students, new ByAgeAscending());

Why does T extends Comparable ? super T include T? Meaning includes ComparableT?

From Lower Bounded Wildcards, a section of the Generics section of The Java Tutorial:

... a lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type.

(bold mine, emphasis theirs)

Thus, the set of classes that match T extends Comparable<T> is a subset of the set of classes that match T extends Comparable<? super T>. The wildcard ? super T itself matches T and any superclasses of T.

In other words, the assumption that "super would only include super class items" is simply incorrect.

Your confusion in the example may also arise from the fact that JTextField is a superclass of JPasswordField; in other words, JPasswordField extends JTextField. The example would match any of the following classes:

  • javax.swing.JPasswordField
  • javax.swing.JTextField
  • javax.swing.JTextComponent
  • javax.swing.JComponent
  • java.awt.Container
  • java.awt.Component
  • java.lang.Object

The example would make much more sense as the following:

void describeComponent(CustomComponent<? super JTextField> ref) {...}

Note that JPasswordField, which is a subclass of JTextField, itself is
omitted in the list of permissible objects, because it is not a
superclass of JTextField.

What does T extends ComparableT mean?

First, you have the Comparable interface which roughly looks like:

public interface Comparable<T> {

int compareTo(T other);
}

As you can see, the type parameter of Comparable is used as the parameter of the compareTo method. Typically, the type argument for T is the same class which is implementing the Comparable interface. This generic setup facilitates comparing instances of the same type with each other. Here's an example:

public class Name implements Comparable<Name> {

@Override
public int compareTo(Name other) {
// compute & return result
}
}

Now let's say you have a method which should return the maximum of two objects according to their natural order. Such a method could look like the following:

public static <U extends Comparable<U>> U max(U left, U right) {
return left.compareTo(right) >= 0 ? left : right;
}

Note: Used U as the type variable instead of T to show it is separate from the T used in the Comparable interface.

The above is a generic method. The type variable U is upper-bounded by Comparable<U>. What this means is that the type argument used in place of U must be assignable to (i.e. subtype of) Comparable<U>. For instance, if we use Name as the type argument it will work because Name is assignable to Comparable<Name>. The reason for specifying the upper-bound as Comparable<U> is that the method needs to call compareTo in order to function properly.

Name name1 = ...;
Name name2 = ...;

Name max = max(name1, name2); // U is inferred to be Name

As shown above, having U as the return type also allows assigning the result to a variable of the same type as the arguments.


Note that for maximum flexibility the max method should actually be declared like so:

public static <U extends Comparable<? super U>> U max(U left, U right) {
return left.compareTo(right) >= 0 ? left : right;
}

The difference being the use of Comparable<? super U> as the upper-bound instead of Comparable<U>. These two Q&As should help explain why using ? super U offers greater flexibility:

  • What is PECS (Producer Extends Consumer Super)?
  • Explanation of generic <T extends Comparable<? super T>> in collection.sort/ comparable code?

Java- The meaning of T extends ComparableT?

This means that the type parameter must support comparison with other instances of its own type, via the Comparable interface.

An example of such a class is provided in the Oracle tutorial Object Ordering. Note the similar pattern to T extends Comparable<T> in the excerpt below:

public class Name implements Comparable<Name> {
...
public int compareTo(Name n) { ... }
}

How return a generic array of T extends Comparable? super T in Java?

The new generic definition in the methods getArray() and findElement() is not needed. You have already defined T on the class level. Define your methods as follows:

public T[] getArray() {
return array;
}

abstract public T findElement() throws IndexingError;

What is ? super T syntax?

super in Generics is the opposite of extends. Instead of saying the comparable's generic type has to be a subclass of T, it is saying it has to be a superclass of T. The distinction is important because extends tells you what you can get out of a class (you get at least this, perhaps a subclass). super tells you what you can put into the class (at most this, perhaps a superclass).

In this specific case, what it is saying is that the type has to implement comparable of itself or its superclass. So consider java.util.Date. It implements Comparable<Date>. But what about java.sql.Date? It implements Comparable<java.util.Date> as well.

Without the super signature, SortedList would not be able accept the type of java.sql.Date, because it doesn't implement a Comparable of itself, but rather of a super class of itself.

Problem with T extends Comparable? super T

Suppose we changed the max method to this:

<T extends Comparable<T>> T max(Collection<? extends T> coll)

You would not be able to get the max of a List<Apple> because Apple does not implement Comparable<Apple>, it implements Comparable<Fruit>. But you and I know perfectly well that an Apple knows how to compare itself to another Fruit because it inherited that functionality.

We fix the problem by changing the declaration of max to this:

<T extends Comparable<? super T>> T max(Collection<? extends T> coll)

This means that we accept any class T such that:

  1. T implements Comparable<T>, or...
  2. T implements Comparable<X> for some X such that X is a super class of T

In order to find the max, we must be sure that any instance of T can safely accept another instance of T as an argument to its compare method.

In the first scenario, it is obvious that any instance of T can safely accept another instance of T as an argument to its compare(T) method.

In the second scenario, any instance of T can safely accept another instance of T as an argument to its compare(X) method because all instances of T are also instances of X.

Your example illustrates the second scenario, where T corresponds to Apple and X corresponds to Fruit.

Using wildcards in Java generics

Forget about Pair for a moment. Let's just look at Comparable. Initially one might think Comparable needs no parameters. But there's a problem in that. What does the signature of compareTo (as in a.compareTo(b)) look like?

Perhaps:

/**
* Return negative if a is 'before' b, positive if a is 'after' b,
* and 0 if they are equal in ranking.
*/
public int compareTo(Object other);
}

But this is problematic: Now for e.g. Double to implement Comparable, it needs to be capable of answering that question for any type. so if I try to compare a Double with value 4.5 against, say, an InputStream - that's a nonsensical question. Asking to compare guns and grandmas.

So, we'd strongly prefer for the signature to be:

/**
* Return negative if a is 'before' b, positive if a is 'after' b,
* and 0 if they are equal in ranking.
*/
public int compareTo(Double other);
}

But how? We can't make a new Comparator interface for every type in existence, and there is nothing in java that means 'your own type'.

Generics to the rescue! Let's make a generics parameter that represents the type against which you can compare yourself:

public interface Comparable<T> {
public int compareTo(T other);

And let's implement it in double:

public class Double extends Number implements Comparable<Double> {
...

We're going to read the type Comparable as: "Comparables of foos", which means: Things which can be compared against things that have the Foo type. (And generally, we just mean Foos with that; we are interested in comparing oranges to oranges, of course).

Now lets stick it back into Pair. We can't write Pair<Comparable> for the same reason you can't write List<List>. Yes, it'll compile, but you get severe warnings: After all, okay a list of lists. But what are the lists in the lists listing? You'd write List<List<String>>: A list of lists of strings. Same applies to comparables: It's not just a Pair of Comparables, it's a Pair of Comparables of Foos. A Pair<Comparable<String>> means: I have a pair of 2 things, each of which is of some type that knows how to compare itself to strings. (And, spoiler alert, only java.lang.String fits that bill).

That juust leaves 2 problems:

  1. Why is it Pair<? extends Comparable<..>> and not just Pair<Comparable>
  2. Why is it Pair<... Comparable<? super T>> and not just Comparable<T>?

The answers to these:

  1. Because of PECS. See the linked answer in the comments.
  2. This is rarely relevant, but in theory, if you have some object of a type that is capable of comparing itself to some SUPERtype of strings (let's say 'can compare itself to any object of any type'), well, that'd.. be just fine. We want anything that knows what to do when I feed it: Hey, compare yourself to this thingie, and the thingie is of type T. Whatever that might be. If the thingie can compare itself to some supertype of T, that's totally fine. All Integers are also Numbers - all Ts are also any supertype of T.

java.util.Comparator.naturalOrder takes a T extends Comparable? super T and returns a ComparatorT - why?

This compiles:

import java.util.*;

class Foo<T extends Comparable<? super T>> {

private Comparator<T> comparator;

public void someMethod(Comparator<T> comparator)
{
this.comparator = comparator; // no compile error
this.comparator = Comparator.<T>naturalOrder(); // <T> is optional, compiler can infer
}
}

The simplest way to think about it is this: you are trying to use type T with the Comparator interface, which imposes certain requirements on it (in particular it has that fancy recursive requirement that T must implement Comparable interface). You do not impose such requirement when genericising (?) your class, so compiler is not happy. Your requirements on T must be as strong as the class that you are using it with.

You are confused about what natural ordering method does. It just takes a class which implements Comparable and creates the default Comparator for it. No way around it -- you can't create a Comparator for something that is not Comparable.

You want TreeMap to require Comparable, but you can't, because it is a valid case to use something that is not comparable, as long as you have provided a Comparator. So TreeMap ends up not enforcing Comparable and just casts explicitly at runtime (and throws an exception).



Related Topics



Leave a reply



Submit