泛型 Oddity - 我可以将 Long 值插入到 Map<String、String>,它可以编译,并且在运行时不会失败
给出以下代码:
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
HashMap<String, Object> dataMap = new HashMap<>();
dataMap.put("longvalue", 5L);
class TestMethodHolder {
<T> T getValue(Map<String, Object> dataMap, String value) {
return (T)dataMap.get(value);
}
}
hashMap.put("test", new TestMethodHolder().<String>getValue(dataMap, "longvalue"));
String value = hashMap.get("test"); // ClassCastException occurs HERE
System.out.println(value);
}
对我来说,这段代码编译并不奇怪,而是ClassCastException出现在get行上,而不是它上面的放置行,尽管我确实对可能发生的事情有一个有根据的猜测。由于泛型类型在运行时被擦除,因此 getValue() 中的强制转换实际上从未在运行时发生,并且实际上是对 Object 的强制转换。如果该方法将按如下方式实现,则将发生运行时强制转换,并且它将在放置行上失败(如预期的那样)。任何人都可以证实这一点吗?
class TestMethodHolder {
String getValue(Map<String, Object> dataMap, String value) {
return (String)dataMap.get(value);
}
}
这是使用泛型的已知缺陷或奇怪之处吗?那么在调用方法时使用<>表示法是不是不好的做法?
编辑:我使用的是默认的Oracle JDK 1.7_03。
上面的另一个隐含问题:原始getValue中的强制转换是否仍在运行时发生,但强制转换实际上是对象 - 或者编译器是否足够聪明,可以消除这种转换,使其在运行时根本不发生?这可以解释人们在运行ClassCastException时注意到的发生位置的差异。