我有一行代码可以编译和运行:
HashMap<String, Object>[] resultArray =
new ObjectMapper().readValue(json, HashMap[].class);
我还有另一行,它给出了Generic array creation error
:
HashMap<String, Object>[] resultArray = new HashMap<String, Object>[] { resultObject };
我知道用Java不可能做到这一点。但是很明显readValue()
地做到了。怎么会这样?
readValue创建了一个原始类型的数组,而HashMap[]
不是HashMap<String, Object>[]
。原始类型是一个相对较低的级别,大多数已过时的功能,应尽可能避免使用。但是对于某些事物,例如反射(杰克逊非常依赖反射),通常是不可能的。
简而言之,杰克逊正在使用一种危险的工具。与许多危险工具一样,它并不总是会造成损坏;否则可能会造成损坏,因此应谨慎使用并有一定的经验。
从本质上讲,这种危险归结为以下事实:对于原始类型,编译器无法跟踪您要使用的实际参数化类型。这意味着它无法保护您避免错误使用它们。
在某个时候,您可能会将此原始数组转换为通用数组。就像是:
HashMap[] original = new HashMap[0];
HashMap<String,Object>[] publiclyVisible = original;
// or
@SuppressWarnings("unchecked")
HashMap<String,Object> singleElement = original[0];
由于擦除的原因,JVM中实际上没有任何东西可以跟踪publiclyVisible
要保存HashMap<String, Object>
s的数组。JVM所知道的只是它拥有一个raw数组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
键的引用(它是整数,因为它偶然是a HashMap<Integer, Foo>
)转换为String时。从本质上讲,程序员希望myMap
所有的键都是字符串,但是擦除和原始类型已经密谋允许它们完全是任何类型。
该问题还有其他变体,以及引发问题的其他令人困惑的方式;但它们都归结为相同的基本问题。简而言之,擦除意味着JVM无法跟踪您引用的实际类型,而原始类型则意味着编译器也无法跟踪它们,并且当您将它们组合在一起时,可能会增加产生令人困惑的错误的可能性。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句