Java泛型:泛型映射(深度副本)的方法签名
我有一些Map
,它们本身也可能包含Map
(任何类型的)。我写了一个带有签名的方法:
public static <K,V> HashMap<K,V> deepCopyHashMap(HashMap<K,V> s);
但是,我现在想对这段代码进行一般化,以支持Map
,但仍然返回与参数类型相同的对象。因此,不是:
public static <K,V> HashMap<K,V> deepCopyHashMap(HashMap<K,V> s);
public static <K,V> CheckedMap<K,V> deepCopyCheckedMap(CheckedMap<K,V> s);
public static <K,V> TreeMap<K,V> deepCopyTreeMap(TreeMap<K,V> s);
...
etc.
我想要这样的东西:
public static <K,V, M extends Map<K,V>> M<K,V> deepCopyMap(M<K,V> s);
然而,这给了我:
Multiple markers at this line
- The type M is not generic; it cannot be parameterized with arguments <K,
V>
- The type M is not generic; it cannot be parameterized with arguments <K,
V>
如何正确声明方法签名并仍然返回正确类型的对象(不在内部使用反射)
对于这个项目,添加更多依赖项实际上不是一个选项,所以我更喜欢不依赖外部库的解决方案。此外,我还研究了Cloneable
接口,但是由于它只是一个标记接口(一般来说没有Map
的实现),所以它对我没有多大用处
编辑:
作为参考,这是我深度复制嵌套HashMap
的代码(代码正常工作):
public static <K,V> HashMap<K,V> deepCopyHashMap(HashMap<K,V> source){
HashMap<K,V> result = new HashMap<K, V>();
for(Map.Entry<K, V> entry : source.entrySet()){
K k = entry.getKey();
V v = entry.getValue();
if(k instanceof HashMap<?,?>){
k = (K) deepCopyHashMap((HashMap<?,?>) k);
}
if(v instanceof HashMap<?,?>){
v = (V) deepCopyHashMap((HashMap<?,?>) v);
}
result.put(k, v);
}
return result;
}
编辑:解决方案
这不是一个理想的解决办法。。如果嵌套的
Map
的运行时类型没有默认构造函数,则它将失败。我已经用嵌套的HashMap
对它进行了测试,并且正确复制了运行时类型@SuppressWarnings("unchecked") public static <K,V, M extends Map<K,V>> M deepCopyMap(M source) throws InstantiationException, IllegalAccessException{ M result = (M) source.getClass().newInstance(); for(Map.Entry<K, V> entry : source.entrySet()){ K k = entry.getKey(); V v = entry.getValue(); if(k instanceof Map<?,?>){ k = (K) deepCopyMap((Map<?,?>) k); } if(v instanceof Map<?,?>){ v = (V) deepCopyMap((Map<?,?>) v); } result.put(k, v); } return result; }
这更安全,但需要明确列出所有已知类型:
@SuppressWarnings("unchecked") public static <K,V, M extends Map<K,V>> M deepCopyMap(M source){ M result; if(source instanceof HashMap){ result = (M) new HashMap<K,V>(); } else { //fail } // etc. add more types here for(Map.Entry<K, V> entry : source.entrySet()){ K k = entry.getKey(); V v = entry.getValue(); if(k instanceof Map<?,?>){ k = (K) deepCopyMap((Map<?,?>) k); } if(v instanceof Map<?,?>){ v = (V) deepCopyMap((Map<?,?>) v); } result.put(k, v); } return result; }
# 1 楼答案
泛型类型参数不能是自泛型的。只需删除
M
的通用定义:您所说的泛型定义
M<K, V>
已经是隐式的,因为编译器必须确保M extends Map<K, V>
为真。因此,定义M<K, V>
是多余的至于在方法内部创建副本,它变得更加复杂。泛型类型提高了泛型方法用户的类型安全性。然而,在这个方法中,你就像使用了一个非泛型的方法,它的参数是原始的
Map
。(当然,您可以进一步重新定义泛型类型。)毕竟,我不会向你推荐你建议的方法。您建议API的用户可以深度克隆作为方法参数提供的任何类型的
Map
。然而,你不能Map
是一个公共接口,任何人都可以实现它。在运行时,可能会要求您创建一个您不知道的深度克隆映射,而您将无法创建。看看这个实现:这对用户来说不是很透明,如果映射包含某些用户类型的映射,则很可能引发异常。编译器会警告您这个方法中的几乎任何内容,这是一个好迹象,表明这是一个坏主意
实际上,我建议您使用重载方法,只为已知类型提供深度克隆。但是,如果发现无法在运行时创建的嵌套映射,则必须抛出运行时异常。你想要的那种类型的安全是很难实现的。此外,我将使其成为合同的一个隐含部分,即当映射类型不在指定的
Map
实现组中时,不能使用嵌套映射附带说明:在不限制
M
和V
的情况下,定义这些参数是没有意义的,因为您对这些参数一无所知。只需使用通配符?
# 2 楼答案
您定义的类型
M
已被绑定为带有<K, V, M extends Map<K, V>>
的Map<K,V>
。所以只要去掉M<K,V>
并把它变成M