I have rewritten this ArrayIndexComparator class based on this answer of Jon Skeet so that it can support generic types: Get the indices of an array after sorting?
public class ArrayIndexComparator<T extends Comparable<? super T>> implements Comparator<Integer> {
private final T[] array;
public ArrayIndexComparator(T[] array) {
this.array = array;
}
public Integer[] createIndexArray() {
Integer[] indexes = new Integer[array.length];
for (int i = 0; i < array.length; i++) {
indexes[i] = i; // Autoboxing
}
return indexes;
}
@Override
public int compare(Integer index1, Integer index2) {
// Autounbox from Integer to int to use as array indexes
return array[index2].compareTo(array[index1]);
}
}
And I can use this class as long as the T type or a supertype of T implements the Comparable interface (Comparable<? super T>).
If I write Comparable<? extends T> instead of Comparable<? super T>, the compiler gives me an error:
@Override
public int compare(Integer index1, Integer index2) {
// Autounbox from Integer to int to use as array indexes
return array[index2].compareTo(array[index1]); // ERROR -> compareTo (capture<? extends T>) in Comparable cannot be applied to (T)
}
What does this compareTo (capture<? extends T>) in Comparable cannot be applied to (T) error mean?
I can assume that it does not make sense to define a class AClass which implements Comparable<AChildClassOfAClass>, but yet it is possible:
class AClass implements Comparable<AChildClassOfAClass> {
@Override
public int compareTo(AChildClassOfAClass o) {
return 0;
}
}
class AChildClassOfAClass extends AClass {
}
In this strange scenario, I assume to be able to use ArrayIndexComparator if I have defined it as ArrayIndexComparator<T extends Comparable<? extends T>>, because in this case T is AClass which implements Comparable<AChildClassOfAClass> which turns out to be a subclass of AClass (therefore Comparable<? extends T> → Comparable<AChildClassOfAClass extends AClass>).
Of course, it makes more sense to use Comparable<? super T>, but I guess I should be able to do it anyway if I want to.
Why doesn't Java allow me to do this?
Thank you very much for your attention.
EDIT: after reading answer to the question Difference between <? super T> and <? extends T> in Java, here is what I understood and I hope I understood it correctly:
array[index1] is of type T but compareTo would expect a type <? extends T>, i.e. an unknown specific type of T (or T itself, but the compiler can't assure that).
Therefore the compiler can't safely cast T to the specific unknown type, whereas it could do it if we use <? super T> because in this case compareTo would expect an unknown supertype of T as a parameter, and as we are passing T, the compiler can safely cast the type T to its supertype as a type T is also a supertype of T (like when we say that an Integer is also a Number, but a Number is not necessarily an Integer).
In this Comparable<? extends T> case we are trying to consume array[index1] by passing it to the compareTo method, but the compiler can't safely cast the type T to the specific type required by compareTo(<? extends T>), which is unknown.
That's why I get the error.
Are this thoughts right?