On 2020-04-20 21:19, Joe Darcy wrote:
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.
Ah, right, and compareTo -- in contrast with equals() -- only compares
to objects of the same type. I think that's part of what confused me here.
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.
Thank you for taking time to explain this!
/Magnus
HTH,
-Joe