Java詳細(xì)分析講解自動(dòng)裝箱自動(dòng)拆箱與Integer緩存的使用
1. 前言
自動(dòng)裝箱和自動(dòng)拆箱是什么?Integer緩存是什么?它們之間有什么關(guān)系?
先來(lái)看一道題目。
Integer a = new Integer(1); Integer b = new Integer(1); System.out.println(a==b); Integer c = 1; Integer d = 1; System.out.println(c==d); Integer e = 128; Integer f = 128; System.out.println(e==f);
先答,后看答案。
答案是false true false,你答對(duì)了嗎?
既然一塊出現(xiàn)了,就一起串一下知識(shí)點(diǎn)
2. 包裝類(lèi)
Java中基本數(shù)據(jù)類(lèi)型有八種,可以分為三類(lèi):
- 字符型:char
- 布爾型:boolean
- 數(shù)值型:byte short int long float double
包裝類(lèi)是將八種基本數(shù)據(jù)類(lèi)型包裝為了類(lèi),使它們可以使用Java的三大特性:封裝、繼承、多態(tài)。對(duì)應(yīng)關(guān)系如下:
基本數(shù)據(jù)類(lèi)型 | 對(duì)應(yīng)的包裝類(lèi) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
數(shù)值型對(duì)應(yīng)的六個(gè)包裝類(lèi)都繼承于Number類(lèi)。
3. 自動(dòng)裝箱與自動(dòng)拆箱
八種基本數(shù)據(jù)類(lèi)型對(duì)應(yīng)八種包裝類(lèi),那么它們是怎么進(jìn)行數(shù)據(jù)轉(zhuǎn)換的?
//基本數(shù)據(jù)類(lèi)型轉(zhuǎn)包裝類(lèi) //1.有參構(gòu)造 Integer a = new Integer(1); //2.實(shí)際上,有參構(gòu)造的參數(shù)也可以是字符串,不過(guò)要使用正確的數(shù)據(jù),“123abc”不可能會(huì)轉(zhuǎn)換為Integer類(lèi)型 Integer b = new Integer("123"); //3.valueOf() Integer c = Integer.valueOf(123); //包裝類(lèi)轉(zhuǎn)基本數(shù)據(jù)類(lèi)型(xxxValue() float是floatValue() double是doubleValue()) int d = a.intValue();
以上的形式都是比較符合認(rèn)知的,獲取一個(gè)對(duì)象可以通過(guò)new或者調(diào)用某個(gè)方法,獲取一個(gè)值就調(diào)用對(duì)象的某個(gè)屬性。
Java 5.0之后可以不用這么麻煩了,增加了自動(dòng)裝箱和自動(dòng)拆箱的新特性,實(shí)際上兩個(gè)概念非常好理解。
int a = 10; Integer b = a; //自動(dòng)裝箱 int c = b; //自動(dòng)拆箱
乍一看,對(duì)象=數(shù)值的這種形式并不符合認(rèn)知,但是借助于自動(dòng)裝箱和自動(dòng)拆箱就可以實(shí)現(xiàn)。實(shí)際上,編譯器還是借助于valueOf()和xxxValue()實(shí)現(xiàn)的。
我們來(lái)看一下valueOf()源碼。
/** * Returns an {@code Integer} instance representing the specified * {@code int} value. If a new {@code Integer} instance is not * required, this method should generally be used in preference to * the constructor {@link #Integer(int)}, as this method is likely * to yield significantly better space and time performance by * caching frequently requested values. * * This method will always cache values in the range -128 to 127, * inclusive, and may cache other values outside of this range. * * @param i an {@code int} value. * @return an {@code Integer} instance representing {@code i}. * @since 1.5 */ public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
valueOf()并不是簡(jiǎn)單地返回Integer對(duì)象,而是先進(jìn)行了一次判斷,輸入的數(shù)據(jù)符合某個(gè)范圍的話,將會(huì)返回一個(gè)特定的對(duì)象,從注釋上來(lái)看,這個(gè)范圍默認(rèn)是[-128,127],并且可能是更大的范圍;而超過(guò)這個(gè)范圍就會(huì)返回new的對(duì)象。而使用到的IntegerCache數(shù)據(jù)就是Integer的緩存了。
4. Interger緩存
數(shù)值計(jì)算日常使用比較頻繁,那如果不停的去new Integer對(duì)象的話,開(kāi)銷(xiāo)會(huì)非常大,所以,Java在執(zhí)行程序時(shí)會(huì)自動(dòng)生成一個(gè)靜態(tài)數(shù)組作為緩存,Integer默認(rèn)對(duì)應(yīng)的緩存數(shù)組范圍在[-128,127],只要數(shù)據(jù)在這個(gè)范圍內(nèi),就可以從緩存中拿到相應(yīng)的對(duì)象。
看一下IntegerCache源碼。
/** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
可以看到,IntegerCache是Integer的靜態(tài)內(nèi)部類(lèi),valueOf()調(diào)用的IntegerCache.cache就是一個(gè)數(shù)組對(duì)象,數(shù)組的大小取決于范圍內(nèi)的最大值和最小值,默認(rèn)是[-128,127],當(dāng)然,(注釋上說(shuō))也可以通過(guò)JVM修改這個(gè)范圍(這我不了解)。然后數(shù)組內(nèi)的元素都會(huì)被賦一個(gè)Integer對(duì)象,緩存也就形成了。
存在數(shù)組緩存,也就意味著,如果取值在[-128,127],使用valueOf()或者自動(dòng)裝箱創(chuàng)建的Integer對(duì)象都是在數(shù)組中取出,因此對(duì)象指向的內(nèi)存地址是完全一樣的。而如果用new或者是超出這個(gè)范圍都要重新創(chuàng)建對(duì)象。
當(dāng)然,不止Integer有緩存機(jī)制,Byte、Short、Long、Character都具有緩存機(jī)制。其中Byte,Short,Integer,Long的范圍為 -128 到 127,Character的范圍為 0 到 127。
5. 回答題目
Integer a = new Integer(1); Integer b = new Integer(1); System.out.println(a==b); Integer c = 1; Integer d = 1; System.out.println(c==d); Integer e = 128; Integer f = 128; System.out.println(e==f);
1.new創(chuàng)建的兩個(gè)對(duì)象,即使值相同,指向的內(nèi)存地址也是不同的,使用==進(jìn)行比較返回結(jié)果為false
2.自動(dòng)裝箱和緩存機(jī)制,兩個(gè)對(duì)象實(shí)際上是相同的,返回結(jié)果為true
3.超出緩存范圍,執(zhí)行時(shí)會(huì)new新對(duì)象,兩個(gè)對(duì)象不同,返回結(jié)果為false
到此這篇關(guān)于Java詳細(xì)分析講解自動(dòng)裝箱自動(dòng)拆箱與Integer緩存的使用的文章就介紹到這了,更多相關(guān)Java自動(dòng)裝箱內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot接收日期類(lèi)型參數(shù)的操作方法
如果使用Get請(qǐng)求,直接使用對(duì)象接收,則可以使用@DateTimeFormat注解進(jìn)行格式化,本文重點(diǎn)給大家介紹springboot接收日期類(lèi)型參數(shù)的方法,感興趣的朋友一起看看吧2024-02-02Java設(shè)計(jì)模式之代理模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java設(shè)計(jì)模式之代理模式,本文詳細(xì)的介紹了什么事代理模式和相關(guān)的類(lèi)和接口,有興趣的可以了解一下2017-08-08淺談Hibernate對(duì)象狀態(tài)之間的神奇轉(zhuǎn)換
這篇文章主要介紹了淺談Hibernate對(duì)象狀態(tài)之間的神奇轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09值得Java開(kāi)發(fā)者關(guān)注的7款新工具
作為老牌語(yǔ)言Java,其生態(tài)圈也出來(lái)了一些有關(guān)云服務(wù)、監(jiān)控、文檔分享方面的工具,這篇文章主要介紹了Java開(kāi)發(fā)者值得關(guān)注的7款新工具,感興趣的小伙伴們可以參考一下2016-07-07Spring MVC的優(yōu)點(diǎn)與核心接口_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Spring MVC的優(yōu)點(diǎn)與核心接口,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08Spring Cloud如何切換Ribbon負(fù)載均衡模式
這篇文章主要介紹了Spring Cloud如何切換Ribbon負(fù)載均衡模式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12Feign調(diào)用服務(wù)時(shí)丟失Cookie和Header信息的解決方案
這篇文章主要介紹了Feign調(diào)用服務(wù)時(shí)丟失Cookie和Header信息的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java將對(duì)象保存到文件中/從文件中讀取對(duì)象的方法
下面小編就為大家?guī)?lái)一篇Java將對(duì)象保存到文件中/從文件中讀取對(duì)象的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12