嵌套映射的 Java 显式转换

标签 java collections casting

为什么这个转换有效?

import java.util.HashMap;
import java.util.Map;

public class TestMap {
    public static void main(String[] args) {
        Map<String, Map<String, Map<String, Map<String,Integer>>>> resultMap = new HashMap<>();
        Map<String, Object> aMap = new HashMap<String, Object>();
        Map<String, Integer> hiddenMap = new HashMap<String, Integer>();
        hiddenMap.put("fortytwo", 42);
        aMap.put("key", hiddenMap);
        resultMap =  (Map<String, Map<String, Map<String, Map<String, Integer>>>>) aMap.get("key");
        System.out.println(resultMap);
    }
}

还有这个:

Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>> resultMap = new HashMap<>();
...
resultMap =  (Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>>) aMap.get("key");

等等……

隐藏的 map 是Map<String, Integer>,这是怎么发生的?成功转换为 Map<String, Map<String, Map<String, Map<String,Integer>>>> resultMap

总是打印:

{fortytwo=42}

这也有效( map 而不是 map ):

public static void main(String[] args) {

        Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>> resultMap = new HashMap<>();
        Map<String, Map> aMap = new HashMap<String, Map>();
        Map<String, Integer> hiddenMap = new HashMap<String, Integer>();
        hiddenMap.put("fortytwo", 42);
        aMap.put("key", hiddenMap);
        resultMap =  (Map<String, Map<String, Map<String, Map<String,Map<String,Integer>>>>>) aMap.get("key");
        System.out.println(resultMap);

    }

编辑:正如@shizhz 所说,这当然是因为类型删除!所以上面的代码等价于:

Map resultMap = new HashMap();
Map aMap = new HashMap();
Map hiddenMap = new HashMap();
hiddenMap.put("fortytwo", 42);
aMap.put("key", hiddenMap);
resultMap = (Map) aMap.get("key");

这也行

最佳答案

因为在编译时使用 java 泛型来提供更严格的类型检查,编译器根据 Type Erasure rules 删除类型参数:

  • 如果类型参数是无界的,则将泛型类型中的所有类型参数替换为它们的边界或 Object。因此,生成的字节码仅包含普通类、接口(interface)和方法。
  • 必要时插入类型转换以保持类型安全。
  • 生成桥接方法以在扩展泛型类型中保留多态性。

在代码中Map<String, Map> aMap = new HashMap<String, Map>(); , aMap 中的值是原始类型 Map ,这意味着当您尝试转换 Map 的原始类型时,编译器不知道它包含什么类型到 Map 的任何泛型类型喜欢Map<String, Integer> ,编译器能做的最好的事情就是给你一个警告。通用类型在编译时被删除,当您从通用映射中获取值时将生成类型转换,因此您只能获取运行时 ClassCastException如果类型不匹配则异常。

让我们看下面的例子:

public static void main(String[] args) {
    Map map = new HashMap();

    map.put("hello", "world");
    map.put(new Integer(1), 1);
    map.put(new Object(), Lists.newArrayList("hello"));

    Map<String, Integer> m =  (Map<String, Integer>) map;
    System.out.println(m);

    Integer i = m.get("hello");// ClassCastException happens at here at runtime
}

我正在尝试转换 Map包含 Map<String, Integer> 的各种键和值但是没有编译错误,在类型删除之后,上面的代码实际上等同于:

public static void main(String[] args) {
    Map map = new HashMap();

    map.put("hello", "world");
    map.put(new Integer(1), 1);
    map.put(new Object(), Lists.newArrayList("hello"));

    Map m = (Map) map;
    System.out.println(m);

    Integer i = (Integer)m.get("hello");
}

现在你可以很容易地看出为什么最后一行导致 ClassCastException .

关于嵌套映射的 Java 显式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43412121/

相关文章:

java - 是否有标准的 Java SE HTML 解析器?如果是这样,为什么要使用非标准的?

java - 这个循环开头的分号是什么意思?

java - 在 Java 中缓存列表(或其他集合)的简单方法是什么

c# - 双重检查字典 "ContainsKey"上的锁定

java - 用整数创建日期然后转换回整数会在 JAVA 中失去精度吗?

c# - 确定如何在 C# 中将对象转换为适当类型的最佳方法?

java - 使用 Byte Buddy 添加具有给定值的注释

java - 为基于 testng 的框架进行测试用例清理的最佳方法

c# - 系统.InvalidOperationException : Collection was modified

c++ - 在 C++ 中将整数填充/嵌入到字符串中