java語言中為每種基本資料類型(int,float,double…)都提供了與之對應的包裝器類型(integer,float,double)。從java se5之後就開始提供了自動裝箱的特性。想要得到一個數值為2016的integer時,隻需要如下的指派語句:
該語句就會自定根據=右邊的數值建立相應的integer,這個過程就是自動裝箱。
拆箱與裝箱是相對應的,即自動将包裝器類型轉換為基本類型,如下指派語句将會觸發拆箱操作
java提供了這樣的文法糖,它到底是怎麼實作的呢,我們可以寫如下代碼進行編譯與反編譯測試
在該java檔案的同級目錄下運作如下指令進行編譯
然後用jd-gui對生成的class檔案進行反編譯,進過編譯->反編譯後的代碼會和我們之前寫的一樣嗎?事實顯示并不一樣。
從結果中可以很清楚的看到,指派語句與之前截然不同,其對a的指派其實是自動調用了integer.valueof()方法,而對n=a這指派語句自動調用了integer.intvalue(),對于其他包裝類型也是如此,自動裝箱與拆箱會自動的調用包裝類中的valueof與xxxvalue方法。
之前已經示範了包裝類型自動裝箱與拆箱的原理。這裡先看下面的代碼,思考一下輸出将會是多少,再進行下一步的讨論。代碼片段摘自《深入了解java虛拟機:jvm的進階特性與最佳實踐》的p274。
輸出的結果是
why?c == d為true,e == f為什麼為false…..
這裡我們進行進一步的讨論。之前我們已經讨論過,integer自動裝箱會自動調用integer.valueof()方法,我們可以檢視其具體實作是怎麼樣的,其源碼如下:
這裡你就會發現,這裡有個判斷,如果輸入的值i在[-128, integercache.high]範圍内時,傳回的是integercache.cache[i + 128];這個integercache是什麼,顯而易見,它是“整型緩存”,也就是說integer類型對[-128, integercache.high]範圍内的數字進行了緩存,進一步看integercache類的源代碼:
從代碼中可以知道,integercache預設對[-128,127] 用了一個cache資料進行了緩存的,緩存最大值h(預設127)可以配置,也就是說-128-127之間的integer都是對cache中的integer包裝類型的一個引用,這裡就可以解釋為什麼system.out.println(c == d); 為true,而 system.out.println(e == f); 為false,因為321顯然>127。
因為緩存最大值是可以配置的,integer類中源碼如是寫道:
我們可以通過-xx:autoboxcachemax=size來進行對緩存最大值進行配置。這裡我們配置為400,重新運作,system.out.println(e == f); 将輸出true。
在看看最後一個system.out.println(g.equals(a+b));為什麼會輸出false,檢視源碼就立即知道答案:
包裝類的equals隻比較同類型的對象。我們對測試代碼進行反編譯
可以看到,傳給equals是基礎int類型,自然傳回的是false。
其他的包裝類型都可以根據上訴方法進行分析,這裡隻給出幾個測試代碼,可以先思考,然後進行實際檢測
java文法糖提供的自動裝箱和拆箱過程,可以通過編譯->反編譯來看其具體是如何進行裝箱和拆箱的,然後對其操作進行源碼檢視,進一步了解其裝、拆過程。