一文帶你深入了解Java的自動(dòng)拆裝箱
什么是自動(dòng)拆裝箱
JDK 1.5開始增加了自動(dòng)拆裝箱機(jī)制,Java保留了一些原始的基本數(shù)據(jù)類型,但由于Java是強(qiáng)面向?qū)ο笳Z(yǔ)言,數(shù)據(jù)類型當(dāng)然也應(yīng)該設(shè)置成對(duì)象才是,所以Java也推出了對(duì)于基本數(shù)據(jù)類型的對(duì)應(yīng)的對(duì)象,將基本數(shù)據(jù)類型轉(zhuǎn)換為對(duì)象就稱為裝箱,反之則是拆箱
八種基本數(shù)據(jù)類型
基本數(shù)據(jù)類型 | 對(duì)象類型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
Java的大部分字節(jié)碼指令都沒有支持類型byte、char和short,甚至沒有任何指令支持boolean類型。
那么Java底層是如何實(shí)現(xiàn)這些數(shù)據(jù)類型的?
事實(shí)上編譯器會(huì)在編譯期或運(yùn)行期搞事
- 將byte和short類型的數(shù)據(jù)帶符號(hào)擴(kuò)展(Sign-Extend)為相應(yīng)的int類型數(shù)據(jù)。
- 將boolean和char類型數(shù)據(jù)零位擴(kuò)展(Zero-Extend)為相應(yīng)的int類型數(shù)據(jù)。
在處理boolean、byte、short和char類型的數(shù)組時(shí),也會(huì)轉(zhuǎn)換為使用對(duì)應(yīng)的int類型的字節(jié)碼指令來(lái)處理。因此,大多數(shù)對(duì)于boolean、byte、short和char類型數(shù)據(jù)的操作,實(shí)際上都是使用相應(yīng)的對(duì)int類型作為運(yùn)算類型來(lái)進(jìn)行的
例如,下面代碼每一行代碼上面的注釋為其部分字節(jié)碼指令
public class Test { /* * 以下均為整型入棧指令 * iconst_1 (-1到5的數(shù)據(jù)使用iconst指令,-1使用iconst_m1指令) * bipush 100 (-128到127[一個(gè)字節(jié)]的數(shù)據(jù)使用bipush指令) * sipush 1000 (-32768到32767[二個(gè)字節(jié)]的數(shù)據(jù)使用sipush指令) * ldc 40000 (-2147483648到2147483647[四個(gè)字節(jié)]的數(shù)據(jù)使用ldc指令) */ public static void main(String[] args) { // bipush 100【將整型數(shù)據(jù)100壓入?!? byte b1 = 100; // bipush 101【將整型數(shù)據(jù)101壓入?!? short s1 = 101; // bipush 49【將整型數(shù)據(jù)49壓入棧】 char c1 = '1'; // iconst_1【將整型數(shù)據(jù)1壓入?!? boolean bl1 = false; } }
自動(dòng)拆裝箱原理
byte與Byte
public class Test { public static void main(String[] args) { Byte num = 1; byte num3 = num; } }
編譯后代碼
public class Test { public static void main(String[] args) { Byte num = Byte.valueOf(1); byte num3 = num.byteValue(); } }
從編譯后代碼可以看出,這兩者的轉(zhuǎn)換用了Byte類中的方法,看一下這兩個(gè)方法
// 靜態(tài)內(nèi)部類 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)); } } private final byte value; public static Byte valueOf(byte b) { // 數(shù)組是不存在負(fù)的下標(biāo)的,所以加上偏移量 final int offset = 128; return ByteCache.cache[(int)b + offset]; } public Byte(byte value) { this.value = value; } public byte byteValue() { return value; }
Byte類在使用的時(shí)候就會(huì)將[-128,127]范圍的Byte對(duì)象緩存進(jìn)類中,這是用了享元模式的思想存取常用的熱點(diǎn)Byte對(duì)象,重復(fù)利用該范圍類的Byte對(duì)象,也就是說(shuō)在這個(gè)數(shù)值范圍的Byte對(duì)象一直是同一個(gè)對(duì)象
short與Short、long與Long、char與Character的轉(zhuǎn)換原理和這個(gè)相同
(char保存的是ASCII碼,所以只緩存[0,127]的對(duì)象)
int與Integer
public class Test { public static void main(String[] args) { Integer num = 1; Integer num2 = 200; int num3 = num; } }
編譯后代碼
public class Test { public static void main(String[] args) { Integer num = Integer.valueOf(1); Integer num2 = Integer.valueOf(200); int num3 = num.intValue(); } }
我們可以看出自動(dòng)拆裝箱事實(shí)上是調(diào)用了Integer類中的方法,來(lái)看一下這兩個(gè)方法,事實(shí)上和byte類似,默認(rèn)[-128,127]的Integer對(duì)象被緩存了,但是IntegerCache.high是可能被人為配置過(guò)的,如果配置的緩存上限值大于127就會(huì)緩存[-128,配置的上限值],在此范圍內(nèi)直接返回緩存的對(duì)象,否則就new一個(gè)新的Integer對(duì)象
public static Integer valueOf(int i) { // IntegerCache.low = -128,IntegerCache.high = 127(默認(rèn)) if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
boolean與Boolean
同樣是這兩個(gè)方法,由于布爾型只有兩個(gè)值,所以直接緩存兩個(gè)對(duì)象
public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); private final boolean value; public Boolean(boolean value) { this.value = value; } public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); } public boolean booleanValue() { return value; }
float與Float以及double與Double
由于浮點(diǎn)數(shù)整數(shù)位相同時(shí)小數(shù)位可以有多種情況,比如整數(shù)位為1的有1.321332,1.543635,..................,數(shù)量太多所以沒有某一個(gè)浮點(diǎn)數(shù)會(huì)被反復(fù)使用,所以沒必要緩存,直接返回一個(gè)Float新對(duì)象
public static Float valueOf(float f) { return new Float(f); } public static Double valueOf(double d) { return new Double(d); }
測(cè)試
我們測(cè)試一下是否返回的是同一個(gè)對(duì)象
public class Test { public static void main(String[] args) { Integer b1 = 10; Integer b2 = 10; Integer b3 = new Integer(10); Integer b4 = new Integer(10); System.out.println(b1 == b2); // true System.out.println(b2 == b3); // false System.out.println(b3 == b4); // false } }
引用類型使用等于比較,比較的是對(duì)象是否相同(基本數(shù)據(jù)類型使用 = 進(jìn)行比較比較的是數(shù)值)
那么b1等于b2說(shuō)明兩個(gè)裝箱類型返回的b1和b2兩個(gè)Integer對(duì)象是同一個(gè)對(duì)象,10這個(gè)數(shù)值在緩存范圍內(nèi)
而使用構(gòu)造方法返回的對(duì)象是兩個(gè)不同的對(duì)象,所以不相同結(jié)果為false
public class Test { public static void main(String[] args) { Integer b1 = 1000; Integer b2 = 1000; System.out.println(b1 == b2);// false } }
而1000這個(gè)數(shù)值已經(jīng)沒有緩存了,所以返回的是兩個(gè)對(duì)象
public class Test { public static void main(String[] args) { Double b1 = 10.0; Double b2 = 10.0; System.out.println(b1 == b2);// false } }
由于Double是沒有用緩存的,所以兩個(gè)對(duì)象一定是不同的
到此這篇關(guān)于一文帶你深入了解Java的自動(dòng)拆裝箱的文章就介紹到這了,更多相關(guān)Java自動(dòng)拆裝箱內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談利用Spring的AbstractRoutingDataSource解決多數(shù)據(jù)源的問題
本篇文章主要介紹了淺談利用Spring的AbstractRoutingDataSource解決多數(shù)據(jù)源的問題,具有一定的參考價(jià)值,有需要的可以了解一下2017-08-08Spring學(xué)習(xí)之開發(fā)環(huán)境搭建的詳細(xì)步驟
本篇文章主要介紹了Spring學(xué)習(xí)之開發(fā)環(huán)境搭建的詳細(xì)步驟,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07springcloud整合seata的實(shí)現(xiàn)代碼
這篇文章主要介紹了springcloud整合seata的實(shí)現(xiàn)方法,整合步驟通過(guò)引入spring-cloud-starter-alibaba-seata?jar包,文中結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05Kafka中的producer攔截器與consumer攔截器詳解
這篇文章主要介紹了Kafka中的producer攔截器與consumer攔截器詳解,Producer 的Interceptor使得用戶在消息發(fā)送前以及Producer回調(diào)邏輯前有機(jī)會(huì)對(duì)消息做 一些定制化需求,比如修改消息等,需要的朋友可以參考下2023-12-12SpringBoot中引入MyBatisPlus的常規(guī)操作
這篇文章主要介紹了SpringBoot中引入MyBatisPlus的常規(guī)操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Java詳解HashMap實(shí)現(xiàn)原理和源碼分析
這篇文章主要介紹了Java關(guān)于HashMap的實(shí)現(xiàn)原理并進(jìn)行源碼分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09Java8實(shí)現(xiàn)對(duì)List<Integer>的求和
這篇文章主要介紹了Java8實(shí)現(xiàn)對(duì)List<Integer>的求和方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05