拋出問題:new Integer(18) 與 Integer.valueOf(18)
?的區別是什么?
new Integer(18)
?每次都會新建一個對象;Integer.valueOf(18)
?會使?用緩存池中的對象,多次調用只會取同?一個對象的引用
Integer x = new Integer(18);
Integer y = new Integer(18);
System.out.println(x == y);Integer z = Integer.valueOf(18);
Integer k = Integer.valueOf(18);
System.out.println(z == k);Integer m = Integer.valueOf(300);
Integer p = Integer.valueOf(300);
System.out.println(m == p);
來看一下輸出的結果吧![]()
除了Float和Double之外,其他的六個包裝器類(Byte、Short、Integer、Long、Character、Boolean)都有常量緩存池。
為什么那兩個沒有呢? 很好思考,緩存這一思想,簡單理解,是把常用的準備好。
首先,Float、Double。都是不可窮舉,就算緩存也不知道緩存1.0、還是1.1等等。但是Boolean,僅僅只有true&false,還有這些整數類都一樣(也不是全緩存,而是都緩存了255)。
- Byte:-128~127,也就是所有的 byte 值
- Short:-128~127
- Long:-128~127
- Character:\u0000 - \u007F
- Boolean:true 和 false
- Integer:-128~127
為了知道為什么,來跟隨筆者閱讀valueof的源碼看看吧(bushi~,還是先看下面的注釋吧)。
@IntrinsicCandidatepublic static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
貼出注釋:
翻譯: 返回一個Integer示例,表示指定的int 值。如果不需要一個新的Integer實例,則通常應優先使用此方法,而不是構造函數Integer(int),因為此方法可能通過緩存頻繁請求的值來產生更好的空間和時間性能。此方法將始終緩存-128到127(包括兩端)范圍內的值,
參數: i 一個 int值
返回值:一個表示Integer的實例 i
自1.5起
從這里發現,我們還需要看看IntegerCache這個靜態內部類的源碼:
private static class IntegerCache {static final int low = -128;static final int high;static final Integer[] cache;static Integer[] archivedCache;static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {h = Math.max(parseInt(integerCacheHighPropValue), 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(h, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;// Load IntegerCache.archivedCache from archive, if possibleCDS.initializeFromArchive(IntegerCache.class);int size = (high - low) + 1;// Use the archived cache if it exists and is large enoughif (archivedCache == null || size > archivedCache.length) {Integer[] c = new Integer[size];int j = low;for(int i = 0; i < c.length; i++) {c[i] = new Integer(j++);}archivedCache = c;}cache = archivedCache;// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}}
同樣,先來看看注釋:
翻譯:
緩存支持JLS要求的自動裝箱的對象標識語義,適用于-128和127之間的值(包含)。緩存在首次使用時初始化。緩存的大小可以通過-XX:AutoBoxCacheMax=<size> 選項來控制。在VM初始化期間,java.lang.Integer.IntegerCache.high屬性可以設置并保存在jdk.internal.misc的私有系統屬性中。VM類。警告:緩存與CDS一起存檔,并在運行時從共享*存檔中重新加載。歸檔緩存(Integer[])和Integer對象位于封閉的歸檔堆區域中。更改實現時應小心,初始化后不應為緩存數組分配新的Integer對象。
說人話:就是通過Integer.valueOf()方法獲取整數對象時,會先檢查該整數是否存在IntegerCache中,如果在,則返回緩存中的對象,否則創建一個新的對象并緩存起來。
?assert IntegerCache.high >= 127;
這里這個assert,是一個關鍵字,寓意是斷言,為了方便表示程序,并不是發布程序的組成部分。
默認情況下,斷言是關閉的,可以在命令行允許java程序時候加入 -ea參數來打開斷言。
來看這個代碼:
public class Test {public static void main(String[] args) {int high = 126;assert high >= 127;}
}
在這里通過命令行,java -ea參數可以看到報錯了。這里我們斷言high>=127.當不滿足時候,就會報錯。實際上不止Java有這種設計,C也有,感興趣的可以去了解。
在Java中,針對一些基本數據類型,Java會在程序啟動時候創建一些常用的對象并緩存在內存中,以提高程序的性能和節省內存開銷。這些常用對象緩存在一個固定的范圍內,超過這個范圍的值會被重新創建新的對象。
使用數據類型緩存池可以有效提高程序的性能和節省內存開銷,但需要注意的是,在特定業務下,緩存池可能帶來一些問題,比如,緩存池中的對象被不同的線程同時修改,導致數據錯誤等問題。因此,實際開發中,需要根據具體的業務需求來決定是否需要使用數據類型緩存池。