When trying to compare a generic type in the form
Class<T> implements Comparable<T> {
public int compareTo(T other){
this.T < other
}
}
does not work for me but when using
Class<T extends Comparable<T>>{
T.compareTo(other.T)
}
does work. I have been unable to deciper why I can't compare T directly using the first example
In your first example:
class Foo<T> implements Comparable<T> {
you're saying that Foo objects are comparable. In your second example:
class Foo<T extends Comparable<T>>{
you're saying that whatever T, is, it's comparable.
Then, in the body of your code, you try to compare things of type T -- in the first case, you have no guarantee that they're comparable, in the second, you do.
I hope these two exmaples will cast some light on your problem:
class Foo<T> implements Comparable<T> {
#Override
public int compareTo(T o) {
// We don't know anything about T
return hashCode() - o.hashCode();
}
}
class Boo<T extends Comparable<? super T>> implements Comparable<T> {
private T instance;
#Override
public int compareTo(T o) {
// We know that T implements Comparable<? super T>
return instance.compareTo(o);
}
}
In first case with Foo, you don't know anything about type T, so you can't do much in your compareTo() method.
However, in Boo, T is required to implement Comparable<? super T> (if you don't know what wildcards are, just think there is simply Comparable<T>), so you can call t.compareTo(anotherT). More about bounded type parameters.
EDIT: (wildard explained)
Consider following code:
class Car implements Comparable<Car> { ... }
class SportCar extends Car { ... }
Now call sportCar1.compareTo(SportCar2) is perfectly legal. However, without the wildcard,
Bar<SportCar> is a cpompile error!
Why? Because SportCar doesn't implement Comparable<SportCar>. And you require T to implement Comparable<T>, and in this case T is SportCar.
But SportCar implements Comparable<Car> and Car is a supertype of SportCar. So you want to say something like "T can be compared to T or any supertype of T" (like in this case SportCar can be compared to any Car).
And that what the wildcard is for (among many other things). Hope this helps.
Related
Can someone explain the difference between <T extends Number & Comparable<T>> and T extends Comparable<? extends Number>?
These look similar to me and both of them compiles fine for sub classes type. The invalid type args shows below error
Type parameter is not within bound parameter;should implement
'java.lang.Number'
and
Type parameter is not within bound parameter; should extend
'java.lang.Comparable>'
respectively.
You won't be able to use:
Comparable<? extends Number>
because the only methods defined by Comparable are consumers (in the sense of PECS): it needs to accept instances of type ? extends Number into its compareTo method - and there is no type which satisfies that bound safely.
Integer is a Comparable<? extends Number>, but so is Double. Thus, you can't safely call instance1.compareTo(instance2) because it would fail if these instances are concretely Integer and Double respectively, since Integer.compareTo can only accept Integer parameters.
As such, the compiler prevents you from calling this method in the first place.
Option 1:
public class A <T extends Number & Comparable<T>>{}
Your Generic Parameter should extend Number and implements Comparable,
which means class A is a Number and Comparable.
Option 2:
public class B <T extends Comparable<? extends Number>>{}
T is Comparable on Numbers(can compare Number only) but doesn't have to be a Number, unlike option 1
I will explain by example:
A
public class A <T extends Number & Comparable<T>>{}
B
public class B <T extends Comparable<? extends Number>>{}
IntegerWrapper(Option 2)
public class IntegerWrapper implements Comparable<Integer> {
Integer number;
public IntegerWrapper(int number) {
this.number = number;
}
#Override
public int compareTo(Integer o) {
return number.compareTo(o);
}
}
GenericsTest
public class GenericsTest {
public static void main(String args[]){
A myA = new A<Integer>();
B myB = new B<IntegerWrapper>();
}
}
I think option 1 is what you are looking for, because i can't think of many useful scenarios for Option 2(Maybe there is...)
I have a generic class C<T> that defines a method doStuff(T arg). I want to define a subclass S that restructs the access to doStuff, let's take the example where it has to be a Number. I've come this far:
public class C<T> {
public void doStuff(T arg) {}
}
public class S<T extends Number> extends C<T> {
public void doStuff(T arg) {
Number n = (Number) arg;
}
}
This means, however, that I have to cast T to Number in my S method. Is there an elegant way to avoid this?
Thanks!
So, a couple of things:
C<T> is unbound.
S<T extends Number> is bound to Number and its children classes.
So, in effect, you've accomplished what you want to do. The casting is unnecessary since T in S is already bound to Number.
To extrapolate it a bit further, if you created other subclasses of C<T> in which you defined the bounds on T...
public class Q<T extends Date> extends C<T>
public class R<T extends Collection> extends C<T>
...all of these classes would have their T bound by whatever's on the right of the extends clause.
Since T is a subclass of Number anyway, you do not have to cast at all. For your example:
public class C<T> {
public void doStuff(T arg) {}
}
public class S<T extends Number> extends C<T> {
public void doStuff(T arg) {
System.out.println(arg instanceof Number);
}
}
doStuff() would always return true then (except arg equals null).
You can completely remove the casting.
If it would not work, the generics would be very weak feature.
Here is the case, I have two classes A, B, and a generic interface C
Class A implements Comparable<A> {...}
interface C<T> {...}
//this class is not longer generic type, I do not know if this matter.
Class B extends A implements C<A> {...}
Then, at other class, I got a B List and sort it as follow
List<B> list = new ArrayList<B>();
Collections.sort(list);
This works perfectly, but now I would like to change the list of B to the generic interface C, so that it can be more general.
List<C<A>> list = new ArrayList<C<A>>();
Collections.sort(list);
This time I got the Error as follow:
Bound mismatch: The generic method sort(List<T>) of type Collections is not
applicable for the arguments (List<C<A>>). The inferred type C<A> is not a
valid substitute for the bounded parameter <T extends Comparable<? super T>>
I have tried the following modifications (of course does not work):
change C to interface C<T> extends Comparable<T>{...}
change B to class B extends A implements C<A>, Comparable<T> {...}
Can anybody help me?
change C to interface C extends Comparable{...}
Class B extends A implements C {...}
As you would have already seen from the error messages, these two won't work together as there will be a conflict in B's definition w.r.t to Comparable<A> and Comparable<C<A>>.
Since A is already implementing Comparable<A>, you can achieve the following
List<C<A>> list = new ArrayList<C<A>>();
Collections.sort(list);
by defining a Comparator for C<A> as follows:
class CTComparator<T> implements Comparator<C<T>>
{
#Override
public int compare(C<T> o1, C<T> o2)
{
return 0;
}
}
and then applying the sort method with this comparator:
List<C<T>> list = new ArrayList<C<T>>();
Collections.sort(list, comparator);
Since C<A> is not having the visibility of the Comparator defined in A hence it's complaining. Define a new comparator of C<A> as blow, it should be fine then.
List<C<A>> list = new ArrayList<C<A>>();
Collections.sort(list, new Comparator<C<A>>() {
#Override
public int compare(C<A> o1, C<A> o2) {
//implement the comarison
return 0;
}
});
If you expect C<T> to be generically comparable based on the type it contains, you should make it comparable on itself (C<T>, not T), but bound its value type to those that implement Comparable. Something like this:
public class C<T extends Comparable<? super T>> extends Comparable<C<T>> {
private final T value;
#Override
public int compareTo(C<T> that) {
return this.value.compareTo(that.value);
}
}
This only makes sense for some containers, such as those that simply wrap a value.
I have this interface
public interface IDataPoint<T> extends Comparable<T> {
public T getValue();
}
and this implementation...
public class IntegerDataPoint implements IDataPoint<Integer> {
// ... some code omitted for this example
public int compareTo(Integer another) {
// ... some code
}
}
and another class...
public class HeatMap<X extends IDataPoint<?> {
private List<X> xPoints;
}
Now I would like to use Collections.max (and similar) on the xPoints list, but that does not work, probably because I got my generics all messed up.
Any suggestions how this could be solved (without a Comparator)?
Collections.max(xPoints);
gives me this error:
Bound mismatch: The generic method max(Collection<? extends T>) of type Collections is not applicable for the arguments (List<X>). The inferred type X is not a valid substitute for the bounded parameter <T extends Object & Comparable<? super T>>
The problem is that Collections.max(Collection<? extends T>) wants the T's to be comparable to themselves not some other type.
In your case IntegerDataPoint is comparable to Integer, but not IntegerDataPoint
You cannot easily fix this because IntegerDataPoint is not allowed to implement Comparable<Integer> and Comparable<IntegerDataPoint> at the same time.
I want to have an interface A parameterised by T A<T>, and also want every class that implements it to also implement Comparable (with T and its subtypes). It would seem natural to write interface A<T> extends Comparable<? extends T>, but that doesn't work. How should I do it then?
When Comparable<? extends T> appears it means you have an instance of Comparable that can be compared to one (unknown) subtype of T, not that it can be compared to any subtype of T.
But you don't need that, because a Comparable<T> can compare itself to any subtype of T anyway, e.g. a Comparable<Number> can compare itself to a Comparable<Double>.
So try:
interface A<T> extends Comparable<T> {
// ...
}
or
interface A<T extends Comparable<T>> extends Comparable<A<T>> {
// ...
}
depending on whether you need to be able to compare instances of T in order to implement your compareTo method.
If you use comparable you do not need to specify the possibility for subtypes in the compare function, it is by nature possible to pass in any subtype of an object X into a method that declared a parameter of class X. See the code below for more information.
public interface Test<T> extends Comparable<T> {
}
class TestImpl implements Test<Number> {
#Override
public int compareTo(final Number other) {
return other.intValue() - 128;
}
}
class TestMain {
public static void main(final String[] args) {
TestImpl testImpl = new TestImpl();
testImpl.compareTo(Integer.MIN_VALUE);
}
}