Java 映射与泛型的递归合并

Java 映射与泛型的递归合并,java,generics,recursion,Java,Generics,Recursion,我正在尝试构建一种方法来合并两个地图的内容。我已经在这里四处寻找了一段时间,但找不到一个通用的方法。我希望尽可能避免使用@SuppressWarnings(“未选中”)注释。我有一个嵌套的映射结构,其中键是字符串,值是更多内容的映射,该结构中的“叶”节点始终是集合。所以在大多数情况下,我有两个结构类似的地图: Map<String,Map<String,Set<String>>> public <T extends Map<String,

我正在尝试构建一种方法来合并两个地图的内容。我已经在这里四处寻找了一段时间,但找不到一个通用的方法。我希望尽可能避免使用
@SuppressWarnings(“未选中”)
注释。我有一个嵌套的映射结构,其中键是字符串,值是更多内容的映射,该结构中的“叶”节点始终是集合。所以在大多数情况下,我有两个结构类似的地图:

Map<String,Map<String,Set<String>>>
    public <T extends Map<String,T>> Map<String,T> merge(final T map1, final T map2)
Map
我想合并这两个映射,这样我就得到了这两个映射的并集,这两个映射中的任何公共键都在结果映射中用一个值表示,该值是两个映射中两个值的合并。在代码中,这是我到目前为止所做的:

@SuppressWarnings("unchecked")
public Map<String,Object> merge(final Map<String, Object> map1,
                                final Map<String, Object> map2) {

    final Map<String,Object> merged = new HashMap<String,Object>(map1);
    for (final Map.Entry<String,Object> entry : merged.entrySet()) {
        final String key = entry.getKey();
        final Object value = entry.getValue();
        if (map2.containsKey(key)) {
            final Object value2 = map2.get(key);
            if ((value instanceof Map) && (value2 instanceof Map)) {
                merged.put(key, merge((Map<String, Object>) value, (Map<String, Object>) value2));
            } else if ((value instanceof Set) && (value2 instanceof Set)) {
                final Set<Object> set = new HashSet<Object>((Set<Object>)value);
                set.addAll((Set<Object>) value2);
                merged.put(key, set);
            } else {
                // throw up, should only ever be a map or a set
            }
       }
    }

    for (final String key : map2.keySet()) {
        if (!merged.containsKey(key)) {
            merged.put(key, map2.get(key));
        }
    }

    return merged;
}
@SuppressWarnings(“未选中”)
公共地图合并(最终地图地图1,
最终地图(地图2){
最终映射合并=新HashMap(map1);
对于(最终映射.Entry:merged.entrySet()){
最后一个字符串key=entry.getKey();
最终对象值=entry.getValue();
if(地图2.containsKey(图例)){
最终对象值2=map2.get(键);
if((映射的值实例)和&(映射的值2实例)){
merged.put(key,merge((Map)value,(Map)value2));
}else if((集合的值实例)和&(集合的值2实例)){
最终集=新哈希集((集)值);
set.addAll((set)值2);
合并。放置(键,集);
}否则{
//呕吐,应该是一张地图或一套
}
}
}
for(最终字符串键:map2.keySet()){
如果(!merged.containsKey(键)){
merged.put(key,map2.get(key));
}
}
返回合并;
}
它确实起到了作用,但我对它不满意,因为使用它时,你会抛出一大堆东西,它还会对你正在使用的集合和映射实现进行假设。假设我知道我一直在处理字符串到某个对象的映射,其中某个对象是一组字符串或另一个字符串到某个对象的映射,我试图找出如何使用泛型来规范这一点。我尝试了其他答案中显示的类似但不完全相同的方法,例如方法签名,如:

Map<String,Map<String,Set<String>>>
    public <T extends Map<String,T>> Map<String,T> merge(final T map1, final T map2)
公共地图合并(最终T地图1,最终T地图2)
但这并没有成功,因为递归调用不喜欢我尝试输入映射为
的参数


我承认以前从来没有必要深入研究泛型。非常感谢您的指导。

我们正在对您正在使用的
集合和
映射实现进行假设:如果您总是创建新的映射和集合,您至少可以避免这种情况——这有一个很好的副作用,即如果有人修改原始集合,就不会破坏您的合并版本

至于您的主要观点,在Java中,没有强制转换就无法做到这一点。泛型不能帮助您,因为在运行时,编译器只知道

Map<String, Object> merge ( Map<String, ?> map1, Map<String, ?> map2 )

我认为你的问题是递归,而不是你提到的T型。Java在泛型中使用enumerate,这意味着当您在运行时执行代码时,类型T将是一个对象。最简单的解决方案可能是使用
Map
作为叶子。@Lonenebula您的意思是
Map
?@Paul我的意思是他可以对所有节点使用
T extends Map
,但是在节点是叶子的情况下,值部分被设置为
null
@Paul不要紧,有些映射不允许
null
-values。是的,我同意,我不认为泛型是解决这个问题的方法。