奇怪的Java題:為什么128 == 128返回為False,而127 == 127會返回為True?
這是我們今天要討論的話題,因為我覺得它非常的有趣。
如果你運行如下代碼:
- class A
- {
- public static void main(String[] args)
- {
- Integer a = 128, b = 128;
- System.out.println(a == b);
- Integer c = 127, d = 127;
- System.out.println(c == d);
- }
- }
你會得到如下結(jié)果:
- false
- true
我們知道,如果兩個引用指向同一個對象,那么==就成立;反之,如果兩個引用指向的不是同一個對象,那么==就不成立,即便兩個引用的內(nèi)容是一樣的。因此,結(jié)果就會出現(xiàn)false。
這是非常有趣的地方。如果你查看Integer.Java類,你會找到IntegerCache.java這個內(nèi)部私有類,它為-128到127之間的所有整數(shù)對象提供緩存。
這個東西為那些數(shù)值比較小的整數(shù)提供內(nèi)部緩存,當進行如此聲明時:
- Integer c = 127
它的內(nèi)部就是這樣的:
- Integer var3 = Integer.valueOf(127);
其實我通過將A.class文件反編譯后,代碼如下圖:
如果我們觀察valueOf()類函數(shù),我們可以看到:
- public static Integer valueOf(int i) {
- if (i >= IntegerCache.low && i <= IntegerCache.high)
- return IntegerCache.cache[i + (-IntegerCache.low)];
- return new Integer(i);
- }
如果值在-128到127之間,它就會返回該緩存的實例。
因此。。。
- Integer c = 127, d = 127;
兩者指向同樣的對象。
這就是為什么下面這段代碼的結(jié)果為true了:
- System.out.println(c == d);
現(xiàn)在你可能會問,為什么會為-128到127之間的所有整數(shù)設(shè)置緩存?
這是因為在這個范圍內(nèi)的小數(shù)值整數(shù)在日常生活中的使用頻率要比其它的大得多,多次使用相同的底層對象這一特性可以通過該設(shè)置進行有效的內(nèi)存優(yōu)化。你可以使用reflection API任意使用這個功能。
運行下面的這段代碼,你就會明白它的神奇所在了。
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
- Class cache = Integer.class.getDeclaredClasses()[0];
- Field myCache = cache.getDeclaredField("cache");
- myCache.setAccessible(true);
- Integer[] newCache = (Integer[]) myCache.get(cache);
- newCache[132] = newCache[133];
- int a = 2;
- int b = a + a;
- System.out.printf("%d + %d = %d", a, a, b); //
- }
打印結(jié)果竟然是:
- 2 + 2 = 5
我們再次看一下反匯編代碼:
是不是又和上面的是同一個問題呢?
但是結(jié)果為什么是 2 + 2 = 5 呢?
我們繼續(xù)去看一下 Integer 源碼,去深入了解 Integer 緩存機制,下面截個圖:
根據(jù)源碼可以發(fā)現(xiàn)***修改 Integer 緩存上限時候的方法有點小瑕疵。我們看看Api給我們怎么建議的一段話:
- the size of the cache may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
原來我們只需要:運行時設(shè)置 -XX:AutoBoxCacheMax=133 就OK。