天天看點

深入了解Java的整型類型:如何實作2+2=5?

先看下這段神奇的Java代碼:

public static void main(String[] args) throws Exception {

      doSomethingMagic();

      System.out.printf("2 + 2 = %d", 2 + 2);

}           
深入了解Java的整型類型:如何實作2+2=5?

執行結果:2 + 2 = 5

深入了解Java的整型類型:如何實作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的一個知識點。

深入了解Java的整型類型:如何實作2+2=5?

可能有的朋友對于doSomethingMagic裡面的代碼有點摸不着頭腦,讓我們先檢視上圖第17行 2 + 2反編譯出來的代碼:

編輯器将2+ 2的值先計算出來,等于4。最後System.out.println列印出來的值,實際上是Integer.valueOf(4)的傳回值。

深入了解Java的整型類型:如何實作2+2=5?

那麼我們就檢視JDK裡Integer.valueOf的實作:

深入了解Java的整型類型:如何實作2+2=5?

上面的實作代碼,從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個元素的值覆寫。

深入了解Java的整型類型:如何實作2+2=5?

我們從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)。

深入了解Java的整型類型:如何實作2+2=5?
深入了解Java的整型類型:如何實作2+2=5?

要擷取更多Jerry的原創技術文章,請關注公衆号"汪子熙"或者掃描下面二維碼:

深入了解Java的整型類型:如何實作2+2=5?
深入了解Java的整型類型:如何實作2+2=5?

繼續閱讀