摘要:整型對象在內(nèi)部實(shí)現(xiàn)中通過使用相同的對象引用實(shí)現(xiàn)了緩存和重用。這種緩存策略僅在自動(dòng)裝箱的時(shí)候有用,使用構(gòu)造器創(chuàng)建的對象不能被緩存。行的結(jié)果為而行則為。所以行的結(jié)果為而行為。中其他類似的緩存的緩存上限可以通過虛擬機(jī)參數(shù)修改,的緩存則沒法修改。
Java5為Integer的操作引入了一個(gè)新的特性,用來節(jié)省內(nèi)存和提高性能。整型對象在內(nèi)部實(shí)現(xiàn)中通過使用相同的對象引用實(shí)現(xiàn)了緩存和重用。
上面的規(guī)則默認(rèn)適用于整數(shù)區(qū)間 -128 到 +127(這個(gè)整數(shù)區(qū)間可以通過啟動(dòng)應(yīng)用的虛擬機(jī)參數(shù)修改:-XX:AutoBoxCacheMax)。這種Integer緩存策略僅在自動(dòng)裝箱(autoboxing)的時(shí)候有用,使用構(gòu)造器創(chuàng)建的Integer對象不能被緩存。Java 編譯器把原始類型自動(dòng)轉(zhuǎn)換為封裝類的過程稱為自動(dòng)裝箱(autoboxing),這相當(dāng)于調(diào)用 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會自動(dòng)拆箱為int,所以為true System.out.println(i == i2); System.out.println(i == i3); System.out.println("**************"); Integer i5 = 127;//java在編譯的時(shí)候,被翻譯成-> Integer i5 = Integer.valueOf(127); Integer i6 = 127; System.out.println(i5 == i6);//true Integer i9 = 128; Integer i10 = 128; System.out.println(i9 == i10);//false Integer ii5 = new Integer(127); System.out.println(i5 == ii5); //false Integer i7 = new Integer(128); Integer i8 = new Integer(123); System.out.println(i7 == i8); //false } }
首先,7行和8行輸出結(jié)果都為true,因?yàn)镮nteger和int比都會自動(dòng)拆箱(jdk1.5以上)。
12行的結(jié)果為true,而15行則為false。java在編譯Integer i5 = 127的時(shí)候,被翻譯成-> Integer i5 = Integer.valueOf(127);所以關(guān)鍵就是看valueOf()函數(shù)了。只要看看valueOf()函數(shù)的源碼就會明白了。JDK源碼的 valueOf函數(shù)式這樣的:
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之間的數(shù),會進(jìn)行緩存,Integer i5 = 127時(shí),會將127進(jìn)行緩存,下次再寫Integer i6 = 127時(shí),就會直接從緩存中取,就不會new了。所以12行的結(jié)果為true,而15行為false。
對于17行和20行,因?yàn)閷ο蟛灰粯?,所以為false。
對于以上的情況總結(jié)如下:
無論如何,Integer與new Integer不會相等。不會經(jīng)歷拆箱過程,i3的引用指向堆,而i4指向?qū)iT存放他的內(nèi)存(常量池),他們的內(nèi)存地址不一樣,所以為false
兩個(gè)都是非new出來的Integer,如果數(shù)在-128到127之間,則是true,否則為false。java在編譯Integer i2 = 128的時(shí)候,被翻譯成-> Integer i2 = Integer.valueOf(128);而valueOf()函數(shù)會對-128到127之間的數(shù)進(jìn)行緩存
兩個(gè)都是new出來的,都為false
int和Integer(無論new否)比,都為true,因?yàn)闀袸nteger自動(dòng)拆箱為int再去比
AutoBoxCacheMax參數(shù)// IntegerCache,Integer類的內(nèi)部類,注意它的屬性都是定義為static final private static class IntegerCache { //緩存的下界,-128,不可變 static final int low = -128; //緩存上界,暫為null static final int high; //緩存的整型數(shù)組 static final Integer cache[]; static { // 緩存上界,可以通過JVM參數(shù)來配置 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); //最大的數(shù)組值是Integer.MAX_VALUE h = 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這個(gè)參數(shù)是設(shè)置Integer緩存上限的參數(shù),在VM初始化期間java.lang.Integer.IntegerCache.high屬性可以被設(shè)置和保存在私有的系統(tǒng)屬性sun.misc.VM class中。理論上講,當(dāng)系統(tǒng)需要頻繁使用Integer時(shí),或者說堆內(nèi)存中存在大量的Integer對象時(shí),可以考慮提高Integer緩存上限,避免JVM重復(fù)創(chuàng)造對象,提高內(nèi)存的使用率,減少GC的頻率,從而提高系統(tǒng)的性能。
理論歸理論,這個(gè)參數(shù)能否提高系統(tǒng)系統(tǒng)關(guān)鍵還是要看堆中Integer對象到底有多少、以及Integer的創(chuàng)建的方式。如果堆中的Integer對象很少,重新設(shè)置這個(gè)參數(shù)并不會提高系統(tǒng)的性能。即使堆中存在大量的Integer對象,也要看Integer對象時(shí)如何產(chǎn)生的。
大部分Integer對象通過Integer.valueOf()產(chǎn)生。說明代碼里存在大量的拆箱與裝箱操作。這時(shí)候設(shè)置這個(gè)參數(shù)會系統(tǒng)性能有所提高。
大部分Integer對象通過反射,new產(chǎn)生。這時(shí)候Integer對象的產(chǎn)生大部分不會走valueOf()方法,所以設(shè)置這個(gè)參數(shù)也是無濟(jì)于事。
JDK中其他類似的緩存Integer的緩存上限可以通過Java虛擬機(jī)參數(shù)修改,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 cache return 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 cache return 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 cache return CharacterCache.cache[(int)c]; } return new Character(c); }
示例:
public class AllCacheDemo { /** * 演示JDK內(nèi)部緩存 */ 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); } }
作者:劉曉;花名:愚谷。
點(diǎn)擊 閱讀更多 查看更多詳情
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/73148.html
摘要:不過其中的流程算是一個(gè)簡易的實(shí)現(xiàn),可以對加深一些理解。實(shí)現(xiàn)二因此如何來實(shí)現(xiàn)一個(gè)完整的緩存呢,這次不考慮過期時(shí)間的問題。緩存數(shù)量超過閾值時(shí)移除鏈表尾部數(shù)據(jù)。 showImg(https://segmentfault.com/img/remote/1460000014229173?w=1408&h=872); 前言 LRU 是 Least Recently Used 的簡寫,字面意思則是最...
摘要:對于數(shù)據(jù)結(jié)構(gòu)哈希表我們在上一篇也已經(jīng)詳細(xì)說了。鍵空間示意圖的數(shù)據(jù)庫就是使用字典哈希表來作為底層實(shí)現(xiàn)的,對數(shù)據(jù)庫的增刪改查都是構(gòu)建在字典哈希表的操作之上的。 前言 只有光頭才能變強(qiáng) 今天繼續(xù)來學(xué)習(xí)Redis,上一篇從零單排學(xué)Redis【青銅】已經(jīng)將Redis常用的數(shù)據(jù)結(jié)構(gòu)過了一遍了。如果還沒看的同學(xué)可以先去看一遍再回來~ 這篇主要講的內(nèi)容有: Redis服務(wù)器的數(shù)據(jù)庫 Redis對過期...
摘要:添加用戶接口類簡單用戶鏈接數(shù)據(jù)庫微服務(wù)通過注解標(biāo)注該類為持久化操作對象。查找用戶數(shù)據(jù)保存用戶數(shù)據(jù)更新用戶數(shù)據(jù)刪除用戶數(shù)據(jù)這是清除緩存添加緩存配置緩存配置。對象是否永久有效,一但設(shè)置了,將不起作用。設(shè)置對象在失效前允許存活時(shí)間單位秒。 SpringCloud(第 045 篇)鏈接Mysql數(shù)據(jù)庫簡單的集成Mybatis、ehcache框架采用MapperXml訪問數(shù)據(jù)庫 - 一、大致介紹...
閱讀 2806·2019-08-30 15:53
閱讀 591·2019-08-29 17:22
閱讀 1218·2019-08-29 13:10
閱讀 2378·2019-08-26 13:45
閱讀 2806·2019-08-26 10:46
閱讀 3244·2019-08-26 10:45
閱讀 2579·2019-08-26 10:14
閱讀 526·2019-08-23 18:23