Generic type parameters cannot be themself generic. Just drop the generic definition for M
:
public static <K, V, M extends Map<K, V>> M deepCopyMap(M s);
The generic definition M<K, V>
you stated is already implicit since the compiler must ensure that M extends Map<K, V>
is true. Therefore, a definition M<K, V>
is redundant.
As for creating a copy inside of the method it gets more complicated. Generic types improve type safety for the users of a generic method. However, inside the method you are just as clueless as if you used a non-generic method which took a raw Map
as its argument. (You could of course further restict the generic types.)
After all, I would not recommend you the approach you suggest. You are suggesting the user of your API that you could deeply clone any type of Map
that is provided as the method's argument. However, you cannot. Map
is a public interface and anybody can implement it. At run time you might be ask to create a deep clone map that is unknown to you and you will not be able to. Look at this implementation:
@SupressWarnings("unchecked")
public static <K, V, M extends Map<K, V>> M deepCopyMap(M s) {
Map map;
if(s.getClass() == HashMap.class) {
map = new HashMap();
} else if(s.getClass == LinkedHashMap.class) {
map = new LinkedHashMap();
} else {
throw new RuntimeException("unknown map type " + s.getClass());
}
for(Map.Entry<K, V> entry : source.entrySet()) {
K k = entry.getKey();
V v = entry.getValue();
if(k instanceof Map) {
map.put(k, deepCopyMap((Map) k));
} else {
result.put(k, v);
}
}
return (M) map;
}
This is not very transperent to the user and will most likely throw an exception if the map contains some user type map. The fact that the compiler will warn you about almost anything in this method is a good sign for that this is a bad idea.
Instead, I would actually recommend you the overloading approach where you only offer deep clones for known types. If you however discover a nested map that you cannot create at run time, you have to throw a run time exception. The kind of type safety you are looking for is hard to achieve. Additionally, I would make it an implicit part of the contract that you cannot use nested maps where the map types are not within a specified group of Map
implementations.
On a side note: Without restricting M
and V
, there is no point in defining these parameters since you do not know anything about these parameters. Simply use a wildcard ?
.