java的封包解包及Integer內部緩存
導語:
之前項目組進行了代碼評審,大家討論的時候有位大神拋出了一個觀點,在使用比較時不要使用封裝類Integer進行比較,容易出問題。因為描述的不是特別清楚,我在家又仔細思考了下。下面是研究成果,與大家分享。
java的自動裝箱
我覺得有必要先解釋一下這個概念,我將從此引申此文的后續。
簡單解釋下封包拆包,其實就是java會自動把基本類型封裝成對象。我百度了下這個關鍵字。第一篇文章是這么寫的:

很簡單吧,但是我寫了個測試類之后發現了個問題。

請看代碼第19到第22行,我們都知道,在java中雙等於==
是比較對象,equals方法是要看調用的對象是否有重寫這個方法,要看實際。
在Integer對象中,equals被這么重寫。

那么問題來了:
System.out.println(c_1 == f_1);// true 有問題,按照我百度的第一篇文章描述c_1和f_1都是new的一個新Integer對象,此處不應該為true
System.out.println(g_1 == h_1);// false 沒問題,==比較對象,雖然值都為1,但都是new出來的Integer,所以對象不同。但如果這樣為什么c和f是true???
所以事實到底是怎么樣的呢,我對class文件進行了反編譯,看到了這樣的內容:

可以看到,當我編寫這樣的代碼時
Integer c_1 = 1;
java最后實際執行的是:
Integer c_1 = Integer.valueOf(1);
而不是我百度來的:
Integer c_1 = new Integer(1);
在讓我們看看valueOf這個方法:

順着找到了一個叫 IntegerCache的內部類:

結合內部類及Integer的valueOf方法,大家應該明白了點什么了吧。
沒錯,實際的邏輯是這樣的:
內部類的靜態代碼塊初始化了一個長度為high+128長度的Integer數組(可以看到high跟環境有關,默認的話是127),當編寫着使用java的自動裝箱這一機制的時候,實際調用的是Integer的valueOf方法,方法會判斷入參是否在范圍內。
如果在范圍內,返回其實是一個靜態數組里的。也就是說Integer c_1 = 1 與 Integer f_1 = 1 返回的其實是同一個對象,而Integer g_1 = 128;由於超過了范圍,是new 的一個新對象。
再回過頭來看看百度的第一篇文章,我可以肯定告訴你,這個是不對的。

我想說的是,百度是個好東西,人家分享知識也是好意。但汲取知識的你更需要抱着懷疑的心態去認真驗證每一個說法,別人的寫的真的不一定就是對的,包裹我上面寫的所有內容。
共勉。
最后最后,其實java中還有很多同樣機制的東西。

