Hello,
On 4/16/2020 5:47 AM, Magnus Ihse Bursie wrote:
[snip]
The tricky one here is the helper TableModelComparator. This one took
me a while to wrap my head around. It implements Comparator, but the
compare() method takes "rows" from the model, which are just expressed
as Objects, and left to subclasses to define differently. For one of
the subclasses it uses the type T that the TableModel is created
around, but in other it uses an independent domain model. :-/ Anyway.
The compare() method then extracts data for the individual columns of
each row using the method getValueForColumn(), and compare them
pairwise. This data from the rows are supposed to implement Comparable.
In the end, I think I got it pretty OK, but I'm still an apprentice
when it comes to generics black magic. The subclasses of
TableModelComparator want to return different objects from
getValueForColumn() for different columns in the row, like Long or
String. They are all Comparable, but String is Comparable<String> and
Long is Comparable<Long>. So I needed to specify the abstract method
as returning Comparable<?>, since Comparable<String> is not
Comparable<Object>.
But then, for reasons that I do not fully fathom, I could not specify
Comparable<?> o1 = getValueForColumn(row1, columns[i]);
Comparable<?> o2 = getValueForColumn(row2, columns[i]);
int result = o1.compareTo(o2);
because the compiler did not accept the call to compareTo().
I did try to sacrifice a black rooster at midnight and walking
backwards in a circle three time, to no avail. Maybe the problem was
that it was not full moon or that I have no cat. In the end, I casted
o1 and o2 to Comparable<Object> and suppressed the warning for that cast.
If anyone knows what rituals I need to perform to make this work, or
-- even better -- how to fix the code properly, please let me know!
A brief discussion of wildcards, ?. The meaning of a wildcard is some
particular unknown type, meeting the various constraints from "?
extends" or "? super". If there is no explicit constraint listed, it is
equivalent to "? extends Object".
So the meaning of the code above is something
Comparable<S> o1 = getValueForColumn(row1, columns[i]);
Comparable<T> o2 = getValueForColumn(row2, columns[i]);
where S and T are two fresh, unrelated type variables. Concretely, this
means S and T could be, say, String and Integer so that is why a call to
o1.compareTo(o2) would not be accepted by the compiler since Strings and
Integer aren't comparable to each other.
While two instances of "Comparable<?>" are syntactically the same, they
don't represent the same type inside the compiler.
In some cases, you can get around this issue by using a separate method
to capture the type variable and then use it more than once. A technique
we've used in the JDK is to have a pubic method with a wildcards calling
a private method using a type variable. I've looked around for a few
minutes and didn't find a concrete example in the JDK, but they're in there.
I haven't looked over the specific code here in much detail; the type
Comparable<Object> might to be the best you can do, but it isn't very
expressive since Object's aren't necessarily comparable.
HTH,
-Joe