Java為每種基本數據類型都提供了對應的對象類型。在Java SE5之前,如果要生成一個數值為7的Integer對象,代碼示例:Integer i = new Integer(7);;Java SE5之後,Java提供了新的語法,簡化了基本數據類型對象的使用,我們稱之為自動裝箱(autoboxing)與拆箱(unboxing)。之前的代碼可以簡化為Integer i = 7;。
Java提供的自動裝箱盒拆箱,是在編譯器層實現的。編譯之後的字節碼仍然是如Java SE5之前的形態。如自動裝箱使用對象的valueOf方法實現的,而拆箱使用對象的 xxxValue方法實現的,xxx代表對應的基本數據類型。
自動裝箱與拆箱的原理很簡單,通常面試會問對象比較的問題,以考察候選人對源碼的了解程度。比較典型的案例是使用==來比較對象是否相等。在實際工作中通常使用對象的equals方法,這是沒有問題的。==操作是比較對象的地址是否相同,只要兩個地址指向的對象不同,==操作就會返回false。
對於基本數據類型的對象來說,由於考慮到有些對象是會經常使用到的,如果頻繁的進行對象的創建和回收,會極大的影響系統效率。因此Java規范也規定需要對於經常使用的對象進行緩存。
對於Integer類型,具體實現中使用了IntegerCache類做緩存,緩存了數值在[-128,127]之間的對象,valueOf方法對於緩存的對象會直接返回對象引用,否則會調用Integer的構造函數創建新對象。因此自動裝箱對於[-128,127]之間的數,使用==操作時會返回true,其他情況是false。但有一點需要注意,如果是直接調用構造方法生成的對象,永遠都是新對象,也就是說==操作都會返回false。
類似的實現,Short、Long、Byte、Integer都是緩存了數值在[-128,127]之間的相應對象;Character對應char類型,沒有負數,因此緩存了[0,127]之間的相應對象;Boolean只有兩個數值,都做了緩存。
至於Double和Float,他們沒有做任何緩存。其原因可能是:
由於在某個范圍內的整型數值的個數是有限的,而浮點數卻不是;
很難評估哪些數是經常被使用到,或者說沒有像整型數值那樣的在實際使用過程中被經常用到的數值;
基於之前的討論,我們知道定義數值類型可以使用Integer i = new Integer(7);或者Integer i = 7;,兩者在使用上主要注意:
前者不會觸發自動裝箱,而後者會觸發自動裝箱過程;
前者直接生成新對象,而後者會根據具體數值,決定是否生成新對象,還是返回緩存對象的引用;
從執行效率和資源占用上來看,後者的效果更高,推薦使用;
另外,在實際工作中,我們還是盡量使用equals方法吧,實在是想不到什麼時候會用==操作啊 (除了面試的時候:))