I came across this question:
We're given a map interface:
interface MyMap<K,V>{
public void put (K key, V value);
public V get (K key);
public boolean containsKey (K key);
}
We want to implement a method addToMyMap
whose signature is (we need to fill in the missing parts (the dots):
void addToMyMap(MYMap<....> m, List<....> keys, .... newValue)
The method will scan the list of keys, and for every key if it doesn't exist in the map it'll add it with newValue as the value.
The implementation that was given as the answer was the following:
public static <K,V> void addToMyMap (MyMap <? super K, ? super V> m, List<? extends K> keys, V newValue)
{
for (K key: keys)
{
if (!m.containsKey(key))
{
m.put(key,newValue);
}
}
}
I'm not entirely sure why this implementation is correct. How can the containsKey
method work if it gets a subclass of K? Isn't it like searching for an Apple
in a List<Fruit>
? How would you even iterate over that list?
The same thing goes for the put
method: How can it iterate over a map with many different types?
This might have to do with the implementation of the Map.
So maybe the real question is how does a map which contains many supertypes of K and V know to iterate over the Ks.
An example for calling this method would be:
MyMap <Number, Number> m = new MyMapImpl<Number,Number>();
m.put(new Integer (1) , new Float(7.2));
m.put (new Float(3.1), new Double(9.99));
List<Integer> lst = new List<Integer>();
lst.add(1); lst.add(2); lst.add(3);
Float f = new Float (55.5);
Util.addToMyMap (m,lst,f);
How can this map, which holds float and integer lookup a key which is of type float (in put and containsKey)?
I'd appreciate some explanation.