需要有关通用阵列创建的帮助

时间:2015-12-25 06:23:33

标签: java generics jackson

我有一行编译和工作的代码:

HashMap<String, Object>[] resultArray = 
        new ObjectMapper().readValue(json, HashMap[].class);

它使用Jackson ObjectMapper

我还有另一行,它提供了Generic array creation error

HashMap<String, Object>[] resultArray = new HashMap<String, Object>[] { resultObject };

我知道在Java中不可能这样做。但显然readValue()以某种方式做到了。怎么会这样?

1 个答案:

答案 0 :(得分:1)

readValue创建了一个原始类型HashMap[] - 而不是HashMap<String, Object>[]的数组。原始类型是一个相对较低级别,大多数过时的功能,如果可能,您应该尽量避免;但是对于某些事情,比如反思(杰克逊严重依赖),它往往是不可能的。

缺点是杰克逊正在玩一种危险的工具。与许多危险工具一样,并不是因为它总是造成损害;它可以造成损害,因此应该谨慎使用并具有一定的经验。

危险本质上归结为这样一个事实:对于原始类型,编译器无法跟踪您想要使用的实际参数化类型;这意味着它无法保护您不正确地使用它们。

在某些时候,您可能会将此原始数组转换为通用数组;类似的东西:

HashMap[] original = new HashMap[0];
HashMap<String,Object>[] publiclyVisible = original;
// or
@SuppressWarnings("unchecked")
HashMap<String,Object> singleElement = original[0];

由于erasure,JVM中实际上没有任何内容可以跟踪publiclyVisible是否包含HashMap<String, Object>数组。所有JVM都知道它拥有一个原始HashMap数组。因此,如果你将Map<Integer, Foo>放入original,JVM会让你;如果有人稍后将其检索为Map<String, Object>,JVM也会很乐意允许这样做。只有当有人试图使用他们遇到麻烦的类型时,它才会以非常明显的方式出现。例如,也许他们会做:

Map<String, Object> myMap = publiclyVisible[0];
for (String key : myMap.keySet()) {
    ...

...他们会在for行上得到一个ClassCastException,说Integer不能转换为String。这非常令人困惑!问题是JVM已经删除了类型信息,因此它无法跟踪任何不正确的数组内容。第一次检测到某些东西是错误的,当它将第一个myMap键的引用 - 这是一个Integer,因为这不小于HashMap<Integer, Foo> - 转换为String时。从本质上讲,程序员希望myMap的所有键都是字符串,但是擦除和原始类型共同允许它们成为任何类型。

该问题还有其他变种,以及触发它的其他令人困惑的方式;但他们都归结为同样的基本问题。简而言之,擦除意味着JVM无法跟踪引用的实际类型,原始类型意味着编译器也无法跟踪它们,当您将它们组合在一起时,可能会增加混淆的可能性错误。