從一道選擇題開始
分析
選項A
選項A中比較的是i01和i02,Integer i01=59這里涉及到自動裝箱過程,59是整型常量,經包裝使其產生一個引用並存在棧中指向這個整型常量所占的內存,這時i01就是Integer 的引用。
而int i02=59由於int是基本類型,所以不存在引用問題,直接由編譯器將其存放在棧中,換一句話說,i02本身就是59。那么System.out.println(i01== i02)結果任何呢?這里涉及到了拆箱的過程,因為等號一邊存在基本類型所以編譯器后會把另一邊的Integer對象拆箱成int型,這時等號兩邊比較的就是數值大小,所以是true。
好了,到了這里,你有沒有想到這樣一個問題:如果是Integer i01=59;Integer i02=59;然后System.out.println(i01== i02)的結果是?可能你會說比較數值大小所以相等啊,也有可能說等號兩邊對象引用,所以比較的是引用,又因為開辟了不同的內存空間,所以引用不同所以返回false。可是正確答案是:true.
再來看這個問題::如果是Integer i01=300;Integer i02=300;然后System.out.println(i01== i02)的結果是? 你可能說上面你不是說了true嘛,怎么還問這樣的問題,可是這次的答案是false。你是否會吃驚?大牛除外,我是小白,求不打臉!
解析:當靠想象無法解決問題的時候,這是就要看源代碼了!!很重要!我們可以在Integer類中找到這樣的嵌套內部類IntegerCache:
private static class IntegerCache {//靜態緩存類 static final int low = -128; static final int high; static final Integer cache[]; static { //靜態代碼塊 // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
這個類就是在Integer類裝入內存中時,會執行其內部類中靜態代碼塊進行其初始化工作,做的主要工作就是把一字節的整型數據(-128-127)裝包成Integer類並把其對應的引用存入到cache數組中,這樣在方法區中開辟空間存放這些靜態Integer變量,同時靜態cache數組也存放在這里,供線程享用,這也稱靜態緩存。
所以當用Integer 聲明初始化變量時,會先判斷所賦值的大小是否在-128到127之間,若在,則利用靜態緩存中的空間並且返回對應cache數組中對應引用,存放到運行棧中,而不再重新開辟內存。
所以對於Integer i01=59;Integer i02=59;**i01 和 i02是引用並且相等都指向緩存中的數據,所以返回true。而對於**Integer i01=300;Integer i02=300;因為其數據大於127,所以虛擬機會在堆中重新new (開辟新空間)一個 Integer 對象存放300,創建2個對象就會產生2個這樣的空間,空間的地址肯定不同導致返回到棧中的引用的只不同。所以System.out.println打印出false。
B選項
從上面的分析,我們已經知道Integer i01=59返回的是指向緩存數據的引用。那么Integer.valueOf(59)返回的是什么或者操作是什么呢?
這個函數的功能就是把int 型轉換成Integer,簡單說就是裝包,那他是新創建一個對象嗎?還是像之前利用緩存的呢?有了之前的經驗,肯定想到的是利用緩存,這樣做既提高程序速度,又節約內存,何樂而不為?
來看一下源代碼:
public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
很明顯跟之前的思想一致,若在-128到127范圍,直接返回該對象的引用,否則在堆中重新new 一個。
到這,System.out.println(i01== i03)的結果毋庸置疑就是true.
選項C
Integer.valueOf(59)返回的是已緩存的對象的引用,而Integer i04 = new Integer(59)是在堆中新開辟的空間,所以二者的引用的值必然不同,返回false,這道題呢就選C
選項D
System.out.println(i02== i04) i02是整型變量,i04是引用,這里又用到了解包,虛擬機會把i04指向的數據拆箱為整型變量再與之比較,所以比較的是數值,59==59,返回true.
學習並轉載自:https://blog.csdn.net/dawn_after_dark/article/details/74154338
對我很有幫助
感謝作者