Java Integer的缓存策略
Java5為Integer的操作引入了一個新的特性,用來節省內存和提高性能。整型對象在內部實現中通過使用相同的對象引用實現了緩存和重用。 上面的規則默認適用于整數區間 -128 到 +127(這個整數區間可以通過啟動應用的虛擬機參數修改:-XX:AutoBoxCacheMax)。這種Integer緩存策略僅在自動裝箱(autoboxing)的時候有用,使用構造器創建的Integer對象不能被緩存。Java 編譯器把原始類型自動轉換為封裝類的過程稱為自動裝箱(autoboxing),這相當于調用 valueOf 方法。
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i); } 復制代碼首先看代碼:
public class TestInteger {public static void main(String[] args) {int i = 128;Integer i2 = 128;Integer i3 = new Integer(128);//Integer會自動拆箱為int,所以為trueSystem.out.println(i == i2);System.out.println(i == i3);System.out.println("**************");Integer i5 = 127;//java在編譯的時候,被翻譯成-> Integer i5 = Integer.valueOf(127);Integer i6 = 127;System.out.println(i5 == i6);//trueInteger i9 = 128;Integer i10 = 128;System.out.println(i9 == i10);//falseInteger ii5 = new Integer(127);System.out.println(i5 == ii5); //falseInteger i7 = new Integer(128);Integer i8 = new Integer(123);System.out.println(i7 == i8); //false} } 復制代碼首先,7行和8行輸出結果都為true,因為Integer和int比都會自動拆箱(jdk1.5以上)。 12行的結果為true,而15行則為false。java在編譯Integer i5 = 127的時候,被翻譯成-> Integer i5 = Integer.valueOf(127);所以關鍵就是看valueOf()函數了。只要看看valueOf()函數的源碼就會明白了。JDK源碼的 valueOf函數式這樣的:
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之間的數,會進行緩存,Integer i5 = 127時,會將127進行緩存,下次再寫Integer i6 = 127時,就會直接從緩存中取,就不會new了。所以12行的結果為true,而15行為false。 對于17行和20行,因為對象不一樣,所以為false。 對于以上的情況總結如下:
- 無論如何,Integer與new Integer不會相等。不會經歷拆箱過程,i3的引用指向堆,而i4指向專門存放他的內存(常量池),他們的內存地址不一樣,所以為false
- 兩個都是非new出來的Integer,如果數在-128到127之間,則是true,否則為false。java在編譯Integer i2 = 128的時候,被翻譯成-> Integer i2 = Integer.valueOf(128);而valueOf()函數會對-128到127之間的數進行緩存
- 兩個都是new出來的,都為false
- int和Integer(無論new否)比,都為true,因為會把Integer自動拆箱為int再去比
AutoBoxCacheMax參數
// IntegerCache,Integer類的內部類,注意它的屬性都是定義為static final private static class IntegerCache {//緩存的下界,-128,不可變static final int low = -128;//緩存上界,暫為nullstatic final int high;//緩存的整型數組static final Integer cache[];static {// 緩存上界,可以通過JVM參數來配置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);//最大的數組值是Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low));}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() {} } 復制代碼-XX:AutoBoxCacheMax這個參數是設置Integer緩存上限的參數,在VM初始化期間java.lang.Integer.IntegerCache.high屬性可以被設置和保存在私有的系統屬性sun.misc.VM class中。理論上講,當系統需要頻繁使用Integer時,或者說堆內存中存在大量的Integer對象時,可以考慮提高Integer緩存上限,避免JVM重復創造對象,提高內存的使用率,減少GC的頻率,從而提高系統的性能。 理論歸理論,這個參數能否提高系統系統關鍵還是要看堆中Integer對象到底有多少、以及Integer的創建的方式。如果堆中的Integer對象很少,重新設置這個參數并不會提高系統的性能。即使堆中存在大量的Integer對象,也要看Integer對象時如何產生的。
JDK中其他類似的緩存
Integer的緩存上限可以通過Java虛擬機參數修改,Byte、Short、Long、Character的緩存則沒法修改。
Byte
private static class ByteCache {private ByteCache(){}static final Byte cache[] = new Byte[-(-128) + 127 + 1];static {for(int i = 0; i < cache.length; i++)cache[i] = new Byte((byte)(i - 128));} }public static Byte valueOf(byte b) {final int offset = 128;return ByteCache.cache[(int)b + offset]; } 復制代碼Short
private static class ShortCache {private ShortCache(){}static final Short cache[] = new Short[-(-128) + 127 + 1];static {for(int i = 0; i < cache.length; i++)cache[i] = new Short((short)(i - 128));} }public static Short valueOf(short s) {final int offset = 128;int sAsInt = s;if (sAsInt >= -128 && sAsInt <= 127) { // must cachereturn ShortCache.cache[sAsInt + offset];}return new Short(s); } 復制代碼Long
private static class LongCache {private LongCache(){}static final Long cache[] = new Long[-(-128) + 127 + 1];static {for(int i = 0; i < cache.length; i++)cache[i] = new Long(i - 128);} }public static Long valueOf(long l) {final int offset = 128;if (l >= -128 && l <= 127) { // will cachereturn LongCache.cache[(int)l + offset];}return new Long(l); } 復制代碼Character
private static class CharacterCache {private CharacterCache(){}static final Character cache[] = new Character[127 + 1];static {for (int i = 0; i < cache.length; i++)cache[i] = new Character((char)i);} }public static Character valueOf(char c) {if (c <= 127) { // must cachereturn CharacterCache.cache[(int)c];}return new Character(c); } 復制代碼示例:
public class AllCacheDemo {/*** 演示JDK內部緩存*/public static void main(String[] args) {Integer a = 28;Integer b = 28;println(a == b);Byte c = 25;Byte d = 25;println(c==d);Short p=12;Short q=12;println(p==q);Long x=127L;Long y=127L;println(x==y);Character m='M';Character n='M';println(m==n);}public static void println(Object o){System.out.println(o);} } 復制代碼作者:劉曉;花名:愚谷。
點擊 查看更多詳情
總結
以上是生活随笔為你收集整理的Java Integer的缓存策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java基本类型与运算
- 下一篇: Shell命令-系统信息及显示之unam