What is the meaning of
class MyMap<K, V> implements Map<Comparable<K>, V>
in class definition? I don't understand how MyMap<K, V> can be a valid implementation of Map<Comparable<K>, V> as MyMap needs K and V whereas Map needs Comparable<K> and V
You're over-analyzing the declaration. K is just any type, and MyMap implements Map<Comparable<K>, V>.
[...] don't understand how MyMap<K, V> can be a valid implementation of Map<Comparable<K>, V> [...]
It can if you implement the methods required by Map<Comparable<K>, V>. In particular MyMap needs to implement a method with the following signature for instance:
public Set<Comparable<K>> keySet() {
...
}
Note that the above method declaration puts no constraint on K. In other words the class declaration should not be confused with
class MyMap<K extends Comparable, V> implements Map<K, V>
which means that K needs to be Comparable.
Related
I am implementing a putAll() method.
I tried to iterate the map using entrySet and iterator methods, but received a compiling error that m.entrySet().iterator() return value could not be converted to Iterator<Entry<? extends K, ? extends V>>.
why? if the map is of that type, it's iterator should be as well, no?
thank you!
doesn't compile:
#Override
public void putAll(Map<? extends K, ? extends V> m) {
Iterator<Entry<? extends K, ? extends V>> iter = m.entrySet().iterator();
while (iter.hasNext()) {
Entry<? extends K, ? extends V> entry = iter.next();
put(entry.getKey(), entry.getValue());
}
}
compiles and works fine:
#Override
public void putAll(Map<? extends K, ? extends V> m) {
Objects.requireNonNull(m, "putAll(): argument is null");
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
Change
Iterator<Entry<? extends K, ? extends V>> iter
To
Iterator<? extends Entry<? extends K, ? extends V>> iter
Think about it this way, each time the method is called, m, which has type Map<? extends K, ? extends V>, points to an object with a "real" type of Map<some actual subtype of K we don't know, some actual subtype of V we don't know>. (These unknown types might be different in each call of the method, but in each call, the passed object must have some specific type for each of the type parameters, though we don't know it.)
Therefore, m.entrySet().iterator() has type Iterator<Map.Entry<some unknown subtype of K, some unknown subtype of V>>. This is not a subtype of Iterator<Map.Entry<? extends K, ? extends V>>, because when the top-level type argument is not a wildcard, the top-level type arguments must match exactly, and they don't here.
Iterator<Map.Entry<some unknown subtype of K, some unknown subtype of V>> is not a subtype of Iterator<Map.Entry<? extends K, ? extends V>> even though Map.Entry<some unknown subtype of K, some unknown subtype of V> is a subtype of Map.Entry<? extends K, ? extends V>, just like how List<String> is not a subtype of List<Object>, even though String is a subtype of Object.
One solution is to add a wildcard at the top level, like in Lino's answer: Iterator<? extends Map.Entry<? extends K, ? extends V>>.
I'm trying to create an implementation of Map that takes collections as keys.
What do you even call this conundrum?
What is the right way to do the class signature?
class SubClass <K extends Collection<E>, V> implements Map<K, V>
^^ Is improper syntax, but indicates what I want to do.
class SubClass <K extends Collection<K>, V> implements Map<Collection<K>, V>
^^ Results in a SubClass for which you can never declare the generic type. K is infinitely recursive. It also doesn't describe the type of behavior I'm looking for.
class SubClass <K , V> implements Map<K, V>
^^ Doesn't enforce the constraint that K needs to be a Collection
class SubClass <K extends Collection, V> implements Map<K, V>
^^ Doesn't allow us to know the generic types of the Collection
class SubClass <E, K extends Collection<E>, V> implements Map<K, V>
^^ Works, but is rather unwieldy
You'll need a type parameter for the Collection element type, potentially a type parameter for the actual Collection type if you need it, and a type parameter for the values.
class SubClass<E, K extends Collection<E>, V> implements Map<K, V> { ... }
If you don't need the specific Collection type, you can use
class SubClass<E, V> implements Map<Collection<E>, V> { ... }
Concerning the various comments on your question
public class Example {
public static void main(String[] args) throws Exception {
Whatever<Self> s = new Whatever<>();
}
}
class Self extends ArrayList<Self> {
}
class Whatever<E extends Collection<E>> {
}
I am trying to implement a generic DDLinkedList of Entries. I have the following classes defined.
class DoublyLinkedList<T extends Comparable<T>>
class DLLNode<T extends Comparable<T>>
Entry<K extends Comparable<K>, V> implements Comparable<Entry<K, V>>
Once I try to create an array of DoublyLinkedlist of type Entry as below:
DoublyLinkedList<DLLNode<Entry<K, V>>> array[] = (DoublyLinkedList<DLLNode<Entry<K, V>>>[]) new DoublyLinkedList[TABLE_SIZE];
I get an error message:
"The type DLLNode<Entry<K,V>> is not a valid substitute for the bounded
parameter <T extends Comparable<T>> of the type DoublyLinkedList<T>"
From my other standing I thought I could make a Generic Type T of Entry.
My question:
Am I going about the wrong way of doing this or am I implementing it wrong?
Your definition for DoublyLinkedList says that it must take a type which is comparable with itself. But your definition for DLLNode does not implement Comparable<DLLNode<T>> which means that DLLNode is not comparable with its own type. So you can't use DLLNode as a parameter type in DoublyLinkedList.
DLLNode needs to actually implement Comparable and not use it as its generic type.
Also your syntax is way off. Arrays cannot use generics. The best you can do is this:
DoublyLinkedList<?> array[] = new DoublyLinkedList[TABLE_SIZE];
You need to do:
class DoublyLinkedList<T extends Comparable<? super T>> {}
class DLLNode<T extends Comparable<? super T>> implements Comparable<DLLNode<T>> {
public int compareTo(DLLNode<T> other) {
return 0;
}
}
abstract class Entry<K extends Comparable<? super K>, V> implements Comparable<Entry<K, V>> {}
class HashEntry<K extends Comparable<? super K>, V> extends Entry<K, V> {
public int compareTo(Entry<K, V> other) {
return 0;
}
}
Then wherever you decide to use this:
DoublyLinkedList<DLLNode<HashEntry<K, V>>> array[] = new DoublyLinkedList[TABLE_SIZE];
The reason why this works is because of that <? super T> declared for the DLLNode class. If you just have <T>, this will not work because HashEntry will not be comparable. Generics in Java is a bit of a pain to get right.
public class IdfMap<K, V> extends HashMap<K, V>{
public IdfMap() {
super();
}
public IdfMap(int initialCapacity){
super(initialCapacity);
}
public IdfMap(int initialCapacity, float loadFactor){
super(initialCapacity, loadFactor);
}
public <K, V extends Comparable<? super V>> SortedSet<Map.Entry<K, V>> entriesSortedByValues(){
SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<>(
new Comparator<Map.Entry<K, V>>() {
#Override
public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2){
return e2.getValue().compareTo(e1.getValue());
}
}
);
sortedEntries.addAll(this.entrySet());
return sortedEntries;
}
}
The line
sortedEntries.addAll(this.entrySet());
does not work. Why? It tells me that the method is not applicable for the given argument, which is a pretty vague error statement to understand. I would except this.entrySet() to return the set, which should in theory be usable for the addAll method.
Your method introduces its own generic type parameters, also called K and V, but completely different from the ones defined by the class.
As a result, within the method, K and V refer to something different from (hence incompatible with) the "real" types.
This is like local variables shadowing member variables. And since they have the same name, the error message becomes hard to understand.
Remove the type parameter declaration from the method, should be
public SortedSet<Map.Entry<K, V>> entriesSortedByValues(){
Read the error message. It says The method addAll(Collection<? extends Map.Entry<K,V>>) in the type Set<Map.Entry<K,V>> is not applicable for the arguments
(Set<Map.Entry<K,V>>)
This is because you are mixing Maps and Sets.
I have a wrapper class for ConcurrentMap like the following:
public MapWrapper<K, V> implements ConcurrentMap<K, V> {
private final ConcurrentMap<K, V> wrappedMap;
...
#Override
public void putAll(Map<? extends K, ? extends V> map) {
wrappedMap.putAll(map); // <--- Gives compilation error
}
...
}
The marked line triggers the following compilation error:
method putAll in interface java.util.Map<K,V> cannot be applied to given types;
required: java.util.Map<? extends capture#5 of ? extends K,? extends capture#6 of ?
extends V>
found: java.util.Map<capture#7 of ? extends K,capture#8 of ? extends V>
reason: actual argument java.util.Map<capture#7 of ? extends K,capture#8 of ? extends V>
cannot be converted to java.util.Map<? extends capture#5 of ? extends K,? extends
capture#6 of ? extends V> by method invocation conversion
I suspect the unbounded wildcards are the culprit but I can't change the method signature since it is inherited from the ConcurrentMap interface. Any ideas?
Have you seen:
What is the difference between bounded wildcard and type parameters?
Let's look to signature of putAll
public void putAll(Map<? extends K, ? extends V> m)
... and to error which you got:
cannot be converted to java.util.Map<? extends capture#5 of ? extends K,? extends
So reason why you can't do it, it's restriction of merging of inheritance tree in Java.
Probably, will be better to write your own implementation of putAll method.
Thanks, hope it will help you.