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?