Reputation: 65813
Trying to design a superclass that ensures all sub-classes are inherently Comparable
.
/**
* A base class implementing Comparable with itself by delegation.
* @param <T> - The type being wrapped.
*/
static class Distinct<T extends Comparable<T>> implements Comparable<Distinct<T>> {
final T it;
public Distinct(T it) {
this.it = it;
}
@Override
public int compareTo(Distinct<T> o) {
return it.compareTo(o.it);
}
}
/**
* A set of distinct items.
*
* @param <T>
*/
static class ThingHolder<T extends Comparable<T>> {
final Set<T> things;
public ThingHolder() {
this.things = new TreeSet<>();
}
}
/**
* A sample real thing.
*/
static class Thing extends Distinct<String> {
public Thing(String it) {
super(it);
}
}
// This doesn't work - Why?
final ThingHolder<Thing> yz = new ThingHolder<>();
The error I get reads:
com/oldcurmudgeon/test/Test.java:[70,22] error: type argument Thing is not within bounds of type-variable T
where T is a type-variable:
T extends Comparable<T> declared in class ThingHolder
Why is this not working? Can it be done?
Upvotes: 4
Views: 155
Reputation: 6332
X
to ThingHolder
it has to be a subtype of Comparable<X>
(by the class declaration of ThingHolder
).Thing
to ThingHolder
it has to be a subtype of Comparable<Thing>
. (Follows from the previous statement by substitution of Thing
for X
.)Thing
extends Distinct<String>
and therefore implements Comparable<Distinct<String>>
(by the class declaration of Thing
).Thing
is not the same type as Distinct<String>
- although it's a subtype - and therefore type matching fails.You could fix this by adjusting the class declaration of ThingHolder
as follows:
class ThingHolder<T extends Comparable<? super T>> {
...
}
Upvotes: 2
Reputation: 65813
Some research and head-bashing brought up this suggestion.
In general, if you have an API that only uses a type parameter T as an argument, its uses should take advantage of lower bounded wildcards (? super T).
Some tinkering (adding ? super T
) to slightly relax the restrictions leaves:
/**
* A set of distinct items.
*
* Don't like the <?> in there but a <T> is not accepted.
*
* @param <T>
*/
static class ThingHolder<T extends Comparable<? super T>> {
final Set<T> things = new TreeSet<>();
}
final ThingHolder<Thing> holder = new ThingHolder<>();
and this is acceptable to the compiler.
Generally I don't like using ?
to paper over the gaps because it usually allows too much through but in this case I will leave it at that.
Upvotes: 1
Reputation: 3048
class ThingHolder<T extends Comparable<T>>
declares that the thing T
must be comparable to itself, but class Thing extends Distinct<String>
isn't.
Upvotes: 0
Reputation: 34900
Just change ThingHolder
class signature to:
static class ThingHolder<T extends Comparable> {
...
}
I.e. remove <T>
from Comparable
, it isn't necessary.
Upvotes: 0