先看下這段神奇的Java代碼:
public static void main(String[] args) throws Exception {
doSomethingMagic();
System.out.printf("2 + 2 = %d", 2 + 2);
}
執行結果:2 + 2 = 5
那麼doSomethingMagic到底做了什麼神奇的事情呢?先看代碼:
private static void doSomethingMagic() throws Exception {
Class cache = Integer.class.getDeclaredClasses()[0];
Field c = cache.getDeclaredField("cache");
c.setAccessible(true);
Integer[] array = (Integer[]) c.get(cache);
array[132] = array[133];
}
是以這個例子其實包含了Java中整型類型Integer的一個知識點。
可能有的朋友對于doSomethingMagic裡面的代碼有點摸不着頭腦,讓我們先檢視上圖第17行 2 + 2反編譯出來的代碼:
編輯器将2+ 2的值先計算出來,等于4。最後System.out.println列印出來的值,實際上是Integer.valueOf(4)的傳回值。
那麼我們就檢視JDK裡Integer.valueOf的實作:
上面的實作代碼,從830行到832行,邏輯非常清楚:如果valueOf的參數i在IntegerCache.low和IntegerCache.high之間,即[-128, 127]的閉區間,則直接從IntegerCache這個緩存區域裡傳回。隻有當輸入參數i不在[-128,127]區間内,才執行代碼832,基于輸入參數i建立一個新的Integer執行個體。
帶着這個理念,我們再看doSomethingMagic就清楚多了。這個方法通過Java反射将上圖IntegerCache的成員cache設定成可通路:setAccessible(true), 然後将IntegerCache的第132個元素的值用第133個元素的值覆寫。
我們從Eclipse調試器裡發現,Integer cache裡第132個元素的值為4,第133個元素的值為5。本來Integer.valueOf方法,對于輸入4,從Integer cache裡傳回第132個元素的值,即4。現在這個元素的值被第133個元素即5覆寫了,是以最後得到了 2 + 2 = 5。
用一句話概括這個場景: 2 + 2 = 4 = Integer.valueOf(4) = 5 ( 因為4在Integer cache裡對應的記錄已經被我們的代碼顯式替換成了5)。