最近在看深入理解JVM,隨手寫了一點代碼,有個問題不太理解。
代碼如下:
public static void main(String[] args) throws Exception {
HashMap<Integer, String> map = new HashMap<Integer, String>();
Method put = HashMap.class.getMethod("put", Object.class, Object.class);
put.invoke(map, 1, new Object());
System.out.println(map);
String val = map.get(1);
System.out.println(val);
}
執行結果(編譯和執行版本都是1.6):
{1=java.lang.Object@2e6e1408}
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
at T002.main(T002.java:12)
報錯是在String val = map.get(1);這一行。
我不解的是:
通過反射,Integer-Object鍵值對竟然正確地放進了Integer-String的HashMap中!
這種不合理的結果,應當是很嚴重的BUG了吧,但是也從沒聽誰提到過。
希望大家多多指點
另外java泛型的機制:
http://irfen.iteye.com/blog/1888312
Java泛型實現原理:類型擦出
Java的泛型是偽泛型。在編譯期間,所有的泛型信息都會被擦除掉。正確理解泛型概念的首要前提是理解類型擦出(type erasure)。
Java中的泛型基本上都是在編譯器這個層次來實現的。在生成的Java字節碼中是不包含泛型中的類型信息的。使用泛型的時候加上的類型參數,會在編譯器在編譯的時候去掉。這個過程就稱為類型擦除。
如在代碼中定義的List<object>和List<String>等類型,在編譯後都會編程List。JVM看到的只是List,而由泛型附加的類型信息對JVM來說是不可見的。Java編譯器會在編譯時盡可能的發現可能出錯的地方,但是仍然無法避免在運行時刻出現類型轉換異常的情況。類型擦除也是Java的泛型實現方法與C++模版機制實現方式(後面介紹)之間的重要區別。
因為是編譯完成的,包括類型檢查這些,而反射繞過了編譯檢查,所以是沒辦法的。