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 in
if you knew the differences between:
List<Object>
and
List<String>
... 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:
public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>>
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.
Lets get a look at interface design first.
public interface Comparable<T> {
public int compareTo(T o);
}
It is quite typical we must say. So if our class needs to implement it we do this.
pubilc class ICanComparteWithMyself implements Comparable<ICanComparteWithMyself> {
public int compareTo(ICanComparteWithMyselfo)
//code for compration
}
As we see the generic parameter type, determine on what we will operate, so for generics we act in the same way
public class ICanCompareMyGeneric<T> implements Comparable<T> {
public int compareTo(T o)
//code for compration
}
}
In your case whawt we want it to assure that generic parameters implements is own Comparable, for that we need to do this
public class MyGenericCanCompareToItself<T extends Comparable<T>> {
}
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
public class ICanCompareStrings implements Comparable<String> {
public int compareTo(String o)
//code for compration
}
}
So for class MyGenericCanCompareToItself
as generic parameter we can use class public MyGenericCanCompareToItself
but not ICanCompareStrings
.
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:
I am a Pair class, that work with two generic parameters, that can use comparison over something that I do not know.
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:
I am a Pair class that works with two parameters, that each of them can be compared with itself.
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 am a Pair class that works with two parameters, that each of them can be compared with classes that deliver from them.
I hope this helps you out with generics ;-).
I would declare my class as such:
public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>>
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:
public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>> {
private T1 key;
private T2 value;
public T1 getKey() {
return key;
}
public T2 getValue() {
return value;
}
public final Comparator<Pair<T1, T2>> KEY_COMPARATOR = new Comparator<Pair<T1, T2>>() {
public int compare(Pair<T1, T2> first, Pair<T1, T2> second) {
return first.getKey().compareTo(second.getKey());
}
};
public static void test() {
Pair<String, Integer> p1 = new Pair<String, Integer>();
Pair<String, Integer> p2 = new Pair<String, Integer>();
p1.KEY_COMPARATOR.compare(p1, p2);
}
}
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.