help with generics - extending hashmap
I'm trying to extend the HashMap class to accept multiple values per key. I'd like .put(key,value) to put a single key/value pair. I'd like .get(key) to return a Vector<V> of all the values associated with key, and .get(key, index) to return a single value of type V for that key. I am using Eclipse 3.2 and Java 1.5.
The problem I am having is my .put(K key,V value) method won't compile, I get the error:
Name clash: The method put(K,V) of type OneToManyHashMap<K,V> has the same erasure as put(K,V> of type HashMap<K,V> but does not override it
My code (roughly):
publicclass OneToManyHashMap<K,V>extends HashMap<K, Vector><V>>{
public V get(Object key,int index){return get(key).get(index);}
public V put(K key, V value){ ...}
public V remove(Object key,int index){return get(key)
}
Yes, I know there is an extra > in the code. It's wasn't there when I typed the message and it's not there when I try and edit the message to remove it :(
Message was edited by:
jiggersplat
I don't think subclassing is logically incorrect here. I would claim you are implementing something that has-a Map < K, List < V > >, not is-a ...
I still get the same compile error with the put method
public class OneToManyHashMap<K,V> implements Map {
private HashMap<K, Vector><V>> map = new HashMap<K,Vector><V>>();
public V get(Object key, int index) { return map.get(key).get(index); }
public V put(K key, V value) { map.get(key).add(value); }
public V remove(Object key, int index) { return map.get(key).remove(index); }
}
> public V put(K key, V value) { map.get(key).add(value); }
This method has a non-void return type, yet you have no return statement.
And I'm not convinced that your class should implement Map, but see how it goes...
yeah, i just omitted the return, regardless that is not the compile error.
this compiles but i don't like it...
public V put(Object key, Object value) { map.get(key).add((V)value); return... }
further more the signature for Map.put in the javadocs is
V put(K key, V value);
Message was edited by:
jiggersplat
There's no need to extend or override anything: Map<Foo, List<Bar>> myMap = new HashMap<Foo, List<Bar>>();
Also, to prevent the extra > characters from being added to your posts, use the < entity instead of <. It's one of several long-standing bugs that the admins can't fix because they're too busy adding new features that nobody wants and that don't work anyway.
Yes, but I don't see how that will support the correct behavior for put and get that I am looking for.
> yeah, i just omitted the return, regardless that is
> not the compile error.
>
> this compiles but i don't like it...
>
> ...
Well, that's too bad. You have to return something whether you like it or not.
thanks for that tip :P
what i meant was i omitted it from the code i posted in the message, not the code i am trying to compile.
anyway, i changed the class definition from
public class MultipleEntryHashMap<K,V> implements Map
to
public class MultipleEntryHashMap<K,V> implements Map<K,V>
I don't think it's possible to turn a Map into a MultiMap by simple extension, given their conflicting semantics. Even using the wrapper technique as you did in reply #2, you still have to implement all the methods of Map. So, for instance, you have to provide get() and remove() methods that don't take index arguments. And if you want to use the added methods that do take indices, you'll have to refer to your MultiMap object by its concrete type, so you lose much of the benefit of extending a built-in collection class.
yeah, most of my methods would look like
public foo bar() {
return map.bar();
}
but get and remove don't do quite what you'd expect. i'm having them return the first value that fits that key, which is not exactly the behavior one would expect from something implementing the map interface. i am starting to agree with you that perhaps implementing the map interface is not appropriate.
This is what was meant by a "has-a" relation:
public class OneToManyHashMap<K, V extends List<V>> {
public Map<K, List<V>> map;
public OneToManyHashMap() { map = new HashMap<K, List<V>>(); }
public V get(K key, int index) { return map.get(key).get(index); }
public void put(K key, V value) { map.get(key).add(value); }
public void remove(K key, int index) { map.get(key).remove(index); }
}
Needless to say, you will have to perform some checks to handle eventual NPE's.
> V extends List<V> ?
Woops, that was when I was trying some other generics-stuff. Forgot to remove it.
It should be this:public class OneToManyHashMap<K, V> {
// ...
}
Thanks BigDaddy.
> ...
> Needless to say, you will have to perform some checks
> to handle eventual NPE's.
... and create and add a new List when a certain key is not yet present in your map.