日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

底层原理_自动装箱与拆箱底层原理

發(fā)布時(shí)間:2025/3/15 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 底层原理_自动装箱与拆箱底层原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.自動(dòng)裝箱與拆箱

??? Java中的數(shù)據(jù)類(lèi)型分為兩大類(lèi),基本數(shù)據(jù)類(lèi)型與引用數(shù)據(jù)類(lèi)型。Java中共提供了八種基本數(shù)據(jù)類(lèi)型,同時(shí)提供了這八種基本數(shù)據(jù)類(lèi)型對(duì)應(yīng)的引用數(shù)據(jù)類(lèi)型。

????自動(dòng)裝箱:基本數(shù)據(jù)類(lèi)型的數(shù)據(jù)自動(dòng)轉(zhuǎn)化為對(duì)應(yīng)的引用數(shù)據(jù)類(lèi)型的數(shù)據(jù)

Integer integerVal = 0;

????自動(dòng)拆箱:引用數(shù)據(jù)類(lèi)型的數(shù)據(jù)自動(dòng)轉(zhuǎn)化為對(duì)應(yīng)的基本數(shù)據(jù)類(lèi)型的數(shù)據(jù)

int intVal = new Integer(0);

????基本數(shù)據(jù)類(lèi)型變量中存儲(chǔ)的就是數(shù)據(jù)值,但是引用數(shù)據(jù)類(lèi)型的變量實(shí)際上指向的是此引用對(duì)象的地址值,那么按照這種思想,賦值的操作應(yīng)該是將對(duì)應(yīng)的數(shù)據(jù)值作為引用地址或者是引用類(lèi)型對(duì)象的地址值賦值給基本數(shù)據(jù)類(lèi)型才對(duì),為什么自動(dòng)裝箱與拆箱的操作就能將其轉(zhuǎn)化成對(duì)應(yīng)的數(shù)據(jù)呢?

????下面就來(lái)說(shuō)一下這種裝箱與拆箱的機(jī)制到底底層是如何實(shí)現(xiàn)的,如何能實(shí)現(xiàn)基本數(shù)據(jù)類(lèi)型與對(duì)應(yīng)引用數(shù)據(jù)類(lèi)型間的自動(dòng)轉(zhuǎn)化。

2.底層原理

????以下剖析原理以int與Integer類(lèi)型為例

????自動(dòng)裝箱的底層原理:自動(dòng)裝箱實(shí)際上調(diào)用的是Integer中的靜態(tài)方法valueOf(),將基本數(shù)據(jù)類(lèi)型的int數(shù)值包裝成了一個(gè)Integer對(duì)象

Integer integerVal = 0;//等效于Integer?integerVal?=?Integer.valueOf(0);

????自動(dòng)拆箱的底層原理:自動(dòng)拆箱的底層實(shí)際上調(diào)用的是Integer對(duì)象的intValue(),得到對(duì)象內(nèi)的int變量的數(shù)值,然后給賦值給變量

int?intVal?=?new?Integer(0);//等效于int?intVal?=?new?Integer(0).intValue();

? ? 說(shuō)到這里,可能很多人知道自動(dòng)裝箱與自動(dòng)拆箱是與這兩個(gè)方法有關(guān),但是空說(shuō)無(wú)憑,下面從字節(jié)碼層面來(lái)看一下,為什么大家都說(shuō)自動(dòng)裝箱與自動(dòng)拆箱與這兩個(gè)方法有關(guān),在哪里能證實(shí)這兩個(gè)方法就是自動(dòng)裝箱與拆箱的本質(zhì)。

3.字節(jié)碼原理探究

(1)字節(jié)碼文件

? ? 剛開(kāi)始學(xué)Java的時(shí)候,大家應(yīng)該都做過(guò)一件事件,那就是編寫(xiě).java源文件,然后使用JDK中提供的javac.exe編譯器將.java源文件編譯成.class文件,class后綴的文件也就是Java中的字節(jié)碼文件,然后使用java.exe工具來(lái)執(zhí)行字節(jié)碼文件。

????也就是說(shuō)JVM中執(zhí)行的實(shí)際上是.class后綴的字節(jié)碼文件,以下就來(lái)解析字節(jié)碼內(nèi)容,查看裝箱與拆箱的本質(zhì)(不懂JVM的朋友也沒(méi)有關(guān)系,可以一起看一下從字節(jié)碼層面來(lái)看,自動(dòng)裝箱與拆箱到底字節(jié)碼中是如何表述的)

(2)自動(dòng)裝箱

?? ?由于字節(jié)碼文件是以二進(jìn)制來(lái)存儲(chǔ)信息的,所以直接打開(kāi)是看不到內(nèi)容的,JDK中提供的javap.exe工具來(lái)將字節(jié)碼文件解析成文本

//源碼public?class?MainClass?{ public static void main(String[] args) { Integer integerVal = 0;????}}//javac編譯得到字節(jié)碼javac MainClass.java//javap解析字節(jié)碼內(nèi)容(-v?-p參數(shù)有興趣的可以自行研究一下)javap -v -p MainClass.clas

????使用javap工具解析后得到解析的內(nèi)容:

????這里只關(guān)注public static void main()方法內(nèi)的內(nèi)容,Code中內(nèi)部的一行行代碼就稱(chēng)之為字節(jié)碼指令

????可以看到在字節(jié)碼層面調(diào)用了Integer.valueOf()方法。

????看到這里就會(huì)發(fā)現(xiàn),其實(shí)編譯過(guò)后,從字節(jié)碼層面所看的行為與源碼的層面還是存在著一定的差異的,這也就是Java為開(kāi)發(fā)人員屏蔽了底層細(xì)節(jié),讓開(kāi)發(fā)人員更加關(guān)注上層的語(yǔ)法,提高開(kāi)發(fā)效率

????從這里也就可以看出,自動(dòng)裝箱的機(jī)制確實(shí)是調(diào)用了Integer.valueOf()方法,將基本數(shù)據(jù)類(lèi)型轉(zhuǎn)化為對(duì)應(yīng)的引用數(shù)據(jù)類(lèi)型

(3)自動(dòng)拆箱

????自動(dòng)拆箱的驗(yàn)證過(guò)程與自動(dòng)裝箱的過(guò)程一樣,需要使用javap.exe工具將字節(jié)碼內(nèi)容解析出來(lái)

//源碼public class MainClass { public static void main(String[] args) { Integer integer = new Integer(0); int intVal = integer; }}//javac編譯得到字節(jié)碼javac MainClass.java//javap解析字節(jié)碼內(nèi)容(-v -p參數(shù)有興趣的可以自行研究一下)javap -v -p MainClass.clas

? ? 使用javap工具解析后得到解析的內(nèi)容:

????前面的字節(jié)碼可以不用看,是創(chuàng)建Integer部分,在標(biāo)記10的位置,調(diào)用了Integer對(duì)象的intValue()方法,這也就是自動(dòng)拆箱的原理,從基本數(shù)據(jù)類(lèi)型自動(dòng)轉(zhuǎn)換到對(duì)應(yīng)的引用數(shù)據(jù)類(lèi)型

????以上所說(shuō)明的是int與Integer類(lèi)型的自動(dòng)裝箱與拆箱原理,其他的幾種基本數(shù)據(jù)類(lèi)型也是一樣的,裝箱與拆箱分別調(diào)用的都是XXX.valueOf()與xxxValue()方法,這里就不一一列舉的,具體的查看細(xì)節(jié)同上

????知道了自動(dòng)裝箱與拆箱的原理,大家應(yīng)該也就能知道下面列舉的代碼的執(zhí)行結(jié)果了:

Integer integerVal = null;int val = integerVal;

4.數(shù)據(jù)緩存池

(1)面試題

????既然聊了基本數(shù)據(jù)類(lèi)型的自動(dòng)裝箱與拆箱這一塊,就順帶來(lái)聊一聊什么是數(shù)據(jù)緩存池

????以下是以前看到過(guò)的一則面試題:

Integer val1 = 127;Integer val2 = 127;Integer val3 = 128;Integer val4 = 128;System.out.println(val1 == val2);System.out.println(val3 == val4);

????剛剛已經(jīng)聊過(guò)了自動(dòng)裝箱問(wèn)題,也就知道這里實(shí)際上是發(fā)生了四次裝箱,得到了四個(gè)Integer對(duì)象。

????既然Integer是引用數(shù)據(jù)類(lèi)型,那么==號(hào)比較的就是這兩個(gè)引用對(duì)象的地址是否相等,但是這里并沒(méi)有任何的引用之間相互賦值,按理說(shuō)應(yīng)該是四個(gè)不相同的對(duì)象,但是結(jié)果卻出人意料

????根據(jù)結(jié)果可以推斷出val1與val2實(shí)際上引用地址是一樣的,但是val3與val4又是不一樣的對(duì)象

????這里的Integer對(duì)象都是由Integer的靜態(tài)方法valueOf()來(lái)創(chuàng)建的,所以就需要看一看valueOf()方法里面到底做了什么,是不是單純地創(chuàng)建對(duì)象那么簡(jiǎn)單。

(2)數(shù)據(jù)緩存池? ?

//Integer.valueOf()源碼public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i);}

????可以看到,在valueOf()方法內(nèi)并不是單純地創(chuàng)建對(duì)象那么簡(jiǎn)單,而是先判斷需要轉(zhuǎn)換的數(shù)據(jù)是否在low~high范圍內(nèi),如果在范圍內(nèi),直接從一個(gè)cache數(shù)組中取出對(duì)應(yīng)槽位中的Integer對(duì)象;如果在此范圍內(nèi)的話,就直接new一個(gè)Integer對(duì)象返回。

????下面再來(lái)看一下IntegerCache的cache數(shù)組到底裝的是什么:

private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static {????????int?h?=?127;????????//...... high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++)????????????cache[k]?=?new?Integer(j++);????????//...... } //......}

??? IntegerCache是Integer中的一個(gè)靜態(tài)內(nèi)部類(lèi),上述省略了部分代碼,只留下了關(guān)鍵性的代碼。

????可以看到在此類(lèi)的靜態(tài)代碼塊中會(huì)創(chuàng)建cache數(shù)組,長(zhǎng)度也就是127-(-128)=255,后續(xù)接著就是一個(gè)循環(huán),也就是初始化輸出,數(shù)據(jù)為-128~127的Integer對(duì)象。

????由于static代碼塊是在程序啟動(dòng)的時(shí)候就會(huì)運(yùn)行的,所以也就是說(shuō),在程序啟動(dòng)的時(shí)候,Integer中的IntegerCache中的cache數(shù)組就被初始化為了-128~127之間,一共255個(gè)Integer對(duì)象。

????再回到valueOf()方法中來(lái)看,判斷數(shù)值是否為-128~127之間,如果是的話,就直接返回cache數(shù)組中對(duì)應(yīng)的Integer對(duì)象,如果在范圍內(nèi),才是new一個(gè)Integer對(duì)象并返回。

????讀到這里,也就能說(shuō)明為什么val1與val2是同一個(gè)對(duì)象,但是val3與val4并不是同一個(gè)對(duì)象了:因?yàn)関al1與val2都是調(diào)用valueOf()方法,參數(shù)都是127,127屬于-128~127之間,所以是直接從IntegerCache.cache數(shù)組中取出創(chuàng)建好的Integer對(duì)象,并且都是從同一個(gè)槽位中取的,所以val1與val2是同一個(gè)對(duì)象;但是128超出了-128~127的范圍,所以不在范圍內(nèi)而直接new了Integer對(duì)象,所以val3與val4都是new的不同的Integer對(duì)象,故不是同一個(gè)對(duì)象

????這里的IntegerCache也就是所謂的數(shù)據(jù)緩存池,起到一定范圍內(nèi)緩存對(duì)象的目的,避免項(xiàng)目中重復(fù)創(chuàng)建相同的Integer對(duì)象,浪費(fèi)空間又損耗性能

其他數(shù)據(jù)數(shù)據(jù)類(lèi)型的緩存池:

????除了Integer中存在數(shù)據(jù)緩存池外,其他的還有Byte、Character、Short、Long

????此外Boolean中的數(shù)據(jù)緩存池比較特殊,由于boolean只有true與false,所以直接定義了兩個(gè)常量TRUE與FALSE,也就是說(shuō),所有使用到的Boolean對(duì)象都是TRUE與FALSE兩個(gè)對(duì)象。

5.總結(jié)

  • 自動(dòng)裝箱指的是基本數(shù)據(jù)類(lèi)型自動(dòng)轉(zhuǎn)化為對(duì)應(yīng)的引用數(shù)據(jù)類(lèi)型

  • 自動(dòng)拆箱指的是引用數(shù)據(jù)類(lèi)型自動(dòng)轉(zhuǎn)化為對(duì)應(yīng)的基本數(shù)據(jù)類(lèi)型

  • 從字節(jié)碼層面發(fā)現(xiàn),自動(dòng)裝箱實(shí)際調(diào)用的是XXX.valueOf()方法將對(duì)應(yīng)的數(shù)據(jù)包裝成對(duì)應(yīng)的對(duì)象;自動(dòng)拆箱是實(shí)際調(diào)用的是對(duì)象的xxxValue()方法返回對(duì)象內(nèi)的基本數(shù)據(jù)類(lèi)型數(shù)據(jù)

  • 自動(dòng)裝箱的時(shí)候,存在一個(gè)數(shù)據(jù)緩存池問(wèn)題,數(shù)據(jù)在一定范圍內(nèi)使用的是緩存池中在程序啟動(dòng)的時(shí)候創(chuàng)建好的對(duì)象,超出范圍才是直接new的對(duì)象

  • 此外,除了基本數(shù)據(jù)類(lèi)型使用“==”號(hào)判斷相等外,引用數(shù)據(jù)類(lèi)型一定要使用equals()方法來(lái)判斷相等(除了特殊情況下需要比對(duì)是否為同一個(gè)對(duì)象的情況下)

????最后,極力推薦有時(shí)間的朋友可以去學(xué)一下JVM(推薦尚硅谷宋紅康老師講的JVM視頻),可能學(xué)習(xí)了JVM你看不到太大實(shí)質(zhì)性地改變,但是對(duì)更多的底層原理有了一定的理解,碰到問(wèn)題的時(shí)候也就不需要死記硬背了,從原理出發(fā)更好地解決問(wèn)題

總結(jié)

以上是生活随笔為你收集整理的底层原理_自动装箱与拆箱底层原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。