I want to write a generic Pair class, which has two members: key and value. The only requirement to this class is that both key and value should implements the Comparable interface, otherwise Pair class will not accept them as type parameter.
First I code it like this:
public class Pair<T1 extends Comparable, T2 extends Comparable>
But the JDK 1.6 compiler will generate warning about this:
Comparable is a raw type. References to generic type Comparable<T> should be parameterized
Then I tried to add type parameters and the code now looks like this:
public class Pair<T1 extends Comparable<? extends Object>,
T2 extends Comparable<? extends Object>>
Now everything go well until I tried to generate an Comparator for Pair.(The following code is in Pair class)
public final Comparator<Pair<T1, T2>> KEY_COMPARATOR = new Comparator<Pair<T1, T2>>() {
public int compare(Pair<T1, T2> first, Pair<T1, T2> second) {
*first.getKey().compareTo(second.getKey());*
return 0;
}
};
The code first.getKey().compareTo(second.getKey());
will generate an error saying:
The method compareTo(capture#1-of ? extends Object) in the type Comparable<capture#1-of ? extends Object> is not applicable for the arguments (T1)
Anyone knows what does this error message mean?
Any hints on this topic are welcome.
UPDATE:
Here is the complete code:
public class Pair<T1 extends Comparable<? extends Object>, T2 extends Comparable<? extends Object>> {
private T1 key;
private T2 value;
public static int ascending = 1;
public final Comparator<Pair<T1, T2>> KEY_COMPARATOR = new Comparator<Pair<T1, T2>>() {
public int compare(Pair<T1, T2> first, Pair<T1, T2> second) {
int cmp = first.getKey().compareTo((T1)(second.getKey()));
if (cmp > 0) return ascending;
return -ascending;
}
};
}
@MarvinLabs Can you explain a bit more why the compiler cannot make sure objects are compared to other objects of the same type. In the above code, second.getKey()
returns T1 type, which is of the same type as first.getKey()
Lets get a look at interface design first.
It is quite typical we must say. So if our class needs to implement it we do this.
As we see the generic parameter type, determine on what we will operate, so for generics we act in the same way
In your case whawt we want it to assure that generic parameters implements is own Comparable, for that we need to do this
As we can see, this is quite common to use. The limitation expected (or not) is that we can work on classes that implement Comparable for it self type. If we had
So for class
MyGenericCanCompareToItself
as generic parameter we can use classpublic MyGenericCanCompareToItself
but notICanCompareStrings
.EDIT:
So when we covered the basics now we can go to solve, your problem
Your class description looks like this
public class Pair<T1 extends Comparable<? extends Object>, T2 extends Comparable<? extends Object>>
This do not have much sensce as is more less the same as
<?>
This description says:
With this code you cann not progress before the generic parameters do not know on that then operate there for you end up with something like this.
first.getKey.compareTo(null);
And this why you code do not compile when you try to cast, the expected type is null.
To change that you need to qualify on what type your generic parameters should be comparable.
For example the can compare on itselft
public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>>
This descriptions says:
And this is what you probably are looking for, additionally they can be compared on something that can be super class of T1 or T2
public class Pair<T1 extends Comparable<? super T1>, T2 extends Comparable<? super T2>>
This description says:
I hope this helps you out with generics ;-).
if you knew the differences between:
and
... it will be easier. basically, they are two different types in java (not "same" List type as you think).
The generic type "logic" is not very straightforward as you think in your mind or as it appears to be.
I think you should declare your "Pair" class as the following:
since you have already made the "T1" T2" comparable, why could you want to implement a Comparator?
if you want to use the "Collections.sort(myCollection, myComparator)", then you don't have to declare that "T1" and "T2" is "comparable"... just make sure your "KEY_COMPARATOR" accepts them...
either way, there is redundancy in the code.
I would declare my class as such:
Meaning that objects are comparable with objects of the same type as they are (your error means that the compiler cannot make sure objects are compared to other objects of the same type).
Your code with my edits compiles properly:
You should however make a separate class (or a static final class) of the comparator so that it is more intuitive to use & also does not increase the weight of each Pair instance.