Java Map<String,Object> 强制转换为 Map<String,String> 不会在运行时抛出错误

Java Map<String,Object> cast to Map<String,String> not throw out error at runtime

private static String tmp = "{\"data\":{\"vin\":\"LNBSCCAK9JD065606\",\"extParameter\":{\"systemTime\":\"2019-01-23 12:58:35\",\"fuelAmount\":20.0},\"pushType\":\"fuelWarn\"},\"type\":\"uaes-iot-public-service\"}";

public static void main(String[] args) {
    JSONObject jsonObject = JSON.parseObject(tmp);
    JSONObject data = JSON.parseObject(jsonObject.getString("data"));
    // line 1
    Map<String, String> result = (Map<String, String>) data.getInnerMap().get("extParameter");

    for (Map.Entry<String, String> item: result.entrySet()) {
        String key = item.getKey();
        // line 2
        String value = item.getValue();
    }
}

以上代码抛出一个

ClassCastExecption at line 2: java.math.BigDecimal cannot be cast to java.lang.String

但是结果类型实际上是Map[String, String],如果map的Value Type不是String,为什么在第1行抛出ClassCastExecption

字段 "fuelAmount" 正在存储十进制值,因此系统正在尝试将您的小数转换为您尝试转换的 String,因此这将引发错误。

结果类型仅为 Map<String, String>,因为您有一个不安全的强制类型转换。会有一个编译器警告。

泛型类型仅在编译时存在,在 运行 时 Map 不检查其组件类型。

String value = item.getValue();

因为是泛型类型,编译器认为这个Map只包含String,所以可以写上面这行。但它实际编译的是

String value = (String) item.getValue(); // cast inserted by compiler

如果值恰好是其他值,这将失败。

"fuelAmount":20.0

这不是 JSON 中的字符串。 您必须自己将其转换为字符串(或处理从 Map 返回的其他类型的值)。

最好的解决方案可能是制作一些 "bean" 类 供 JSON 解析器反序列化。这些可以具有命名和类型属性。