Generic method to Sort a Map on Values
I have a small program that is supposed to sort a map based on its values. Here is what I have so far:
public static <K, V extends Comparable< ? extends V>> Map<K, V>
sortByValues(final Map <K, V> mapToSort)
{
List<Map.Entry<K, V>> entries =
new ArrayList<Map.Entry<K, V>>(mapToSort.size());
entries.addAll(mapToSort.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<K, V>>()
{
public int compare(
final Map.Entry<K, V> entry1,
final Map.Entry<K, V> entry2)
{
return entry1.getValue(开发者_开发知识库).compareTo(entry2.getValue());
}
});
Map<K, V> sortedMap = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : entries)
{
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
I want my generic value V to be comparable to anything that is either V or is a at least a subclass of V.
I get the following error for the code piece :
public static <K, V extends Comparable< ? extends V>>
Bound mismatch: The method compareTo(? extends V) of type V is not applicable for the arguments (V). The wildcard parameter ? extends V has no lower bound, and may actually be more restrictive than argument V
How can it be more restrictive?
If I change the declaration to:
public static <K, V extends Comparable< ? super V>>
then there is no error. But this is not what I want.
One workaround I have is that, I can change the declaration to:
public static <K, V extends Comparable<V>>
but doing this I lose the flexibility in that I cannot pass a Map whose value implements Comparable with a subclass of itself.
Apologies for such a long question. Thanks in advance.
I think your second option, namely
public static <K, V extends Comparable<? super V>>
is the way to. I think this is so because when you write
public static <K, V extends Comparable<C extends V>>
you basically say that you want to be able to compare any instance of V
to any instance of C
. But what is missing here is, that because you want to call Collections.sort(..)
internally, you also must be able to compare any instance of C
to any instance of V
. But the generics do not express this, and rightfully the compiler complains.
Basically, to sort some values (at least using Collections.sort(..)
) they must be mutually comparable, but the generic restrictions you envision only guarantee that you can compare in one direction.
implements Comparable with a subclass of itself.
This is "poor design": As a good general rule, classes should not know about their subclasses.
What use case do you have in mind?
I think public static <K, V extends Comparable<V>>
is fine.
I think you wanted V to be an extension of some type T. Try adding a temporary type T, as follows in the template declaration:
public static <K, T extends Comparable<T>, V extends T> Map<K, V>
sortByValues(final Map <K, V> mapToSort)
everything else remains the same. If you didn't mean that, that is all your Comparables are going to be a sub type of V, then public static <K, V extends Comparable<V>>
makes sense, because from V's point of view, the child class of V that overrides compareTo is going to call the compareTo method with the same signature as the compareTo method that V has. Ie, The compareTo method that V declares is what is going to be called (but it may be the overridden definition in V's child class). And so, V extends Comparable<V>
is sufficient and correct. I hope I've made myself clear.
精彩评论