Java Collections.synchronizedMap() with complex type definition
Suppose I have a class of the sort:
public class MyMap<K, V> implements Map<Set<K>, V> {
...
}
and I'd like to be able to enforce synchronisation on it. One way is to internally synchronise the methods (perhaps with the synchronized keywords), but if I intend it for more general usage, then it might be better to use external synchronisation, perhaps with the Collections.synchronizedMap() method.
The problem arises in the class where I try to implement this: suppose I have the following class:
public class Foo {
MyMap<String, Object> _myMap;
public Foo() {
_myMap = Collections.synchronizedMap(new MyMap<String, Object>());
}
}
On line 4 of the class, I get the error "Type mismatch: cannot convert from Map< Set < String>, Object> to MyMap< String, Object>". Eclipse suggests that I do one of two things: either add a cast to MyMap< String, Object>, or change the type of _myMap to Map< Set < String>, Object>. However, I obviously do not want to do the latter, since the whole point of using MyMap rather than Map is so that I can take advantage of the additional features I have implemented in MyMap. Then, when I try to add the cast as they suggest, so that the line now looks like
_myMap = (MyMap<String, Object>) Collections.synchronizedMap(new MyMap<String, Object>);
I get the following error when the code actually executes:
java.lang.ClassCastException: java.util.Collections$SynchronizedMap cannot be cast to ****.MyMap
It appears that the synchronizedMap() is downcasting(?) the MyMap to its "true" type, which is Map< Set< String>, 开发者_StackOverflowObject>>, and then not allowing me to cast it back to a MyMap, which is what type I passed into synchronizedMap().
Is there any way around these to hack synchronizedMap to work with this kind of class? If not, what might be a recommended method of achieving external or synchronisation?
Perhaps as a follow-up question, is this method of implementing an interface where the type parameters are not simple types (for example the nontrivial Set< K> in the first Map parameter) commonly used in practice? Can the implementing class (MyMap in this case) ever be parametrised with anything other than simple types -- in other words, even if one is implementing something like Map< Set< K>, V>
, can the implementing class ever have something other than < K, V> as its parameters (additional unused parameters notwithstanding)?
On a completely unrelated side note, does anyone know how I can get around the weird tag capturing (so that I don't have to put spaces like "Map< K, V>"), even when I enclose it with blocks?
If you check out the javadocs for Collections.synchronizedMap (see here) then you will see how you are actually supposed to use this and what it does. The main thing to note is that the Map you pass through is wrapped in a new synchronized implementation of Map and this implementation is not the same as MyMap so that is why the explicit cast fails.
As for a solution to your problem, I am not 100% certain what you are looking for but will a simple ConcurrentHashMap not be sufficient? Have a look here for the javadocs.
The problem is that you are defining your field as " MyMap". If you intend to use external synchronization, then you must use only Map, and you can not even cast to MyMap later.
The reason is that SynchronizedMap will not actually "add" synchronization to your class, but return a new Map implementation, synchronized, wrapping the map instance you pass as a parameter.
精彩评论