摘要:本章部分內(nèi)容從源碼中解讀一些自動(dòng)裝箱與拆箱的原理,以及會(huì)出現(xiàn)的一些陷阱已經(jīng)性能等。例題分析我們通過(guò)幾個(gè)經(jīng)典的問(wèn)題,來(lái)看看大家到底理解了裝箱與拆箱的知識(shí)點(diǎn)沒(méi)。
每章一點(diǎn)正能量:每當(dāng)你想要放棄的時(shí)候,就想想是為了什么才一路堅(jiān)持到現(xiàn)在。前言
最近在回顧復(fù)習(xí)Java基礎(chǔ)中的一些知識(shí)點(diǎn),發(fā)現(xiàn)了一些以前見(jiàn)過(guò)但是沒(méi)有留意卻特別有意思的知識(shí)特性,比如這次想分享的Java中一個(gè)常見(jiàn)的特性:自動(dòng)裝箱與拆箱。這個(gè)知識(shí)點(diǎn)和特性其實(shí)在我們開(kāi)發(fā)過(guò)程中經(jīng)常會(huì)遇到。同時(shí)我們也會(huì)去使用一些基本數(shù)據(jù)類(lèi)型或者是封裝數(shù)據(jù)類(lèi)型,但是對(duì)于他們之間的一些轉(zhuǎn)換等特性可能不是特別清楚。也可能出現(xiàn)在我們的面試中。本章部分內(nèi)容從源碼中解讀一些自動(dòng)裝箱與拆箱的原理,以及會(huì)出現(xiàn)的一些陷阱已經(jīng)性能等。如有錯(cuò)誤還請(qǐng)大家及時(shí)指出~
本文已同步至 GitHub/Gitee/公眾號(hào),感興趣的同學(xué)幫忙點(diǎn)波關(guān)注~
問(wèn)題:
基本數(shù)據(jù)類(lèi)型與封裝數(shù)據(jù)類(lèi)型有哪些區(qū)別?
什么是裝箱?什么是拆箱?
裝箱和拆箱都是如何實(shí)現(xiàn)的?
使用時(shí)需要注意哪些問(wèn)題?
1.基礎(chǔ)知識(shí)回顧Java把內(nèi)存劃分成兩種:一種是棧內(nèi)存,另一種是堆內(nèi)存。
int是基本類(lèi)型,直接存數(shù)值;而 Integer是類(lèi),產(chǎn)生對(duì)象時(shí)用一個(gè)引用指向這個(gè)對(duì)象。
封裝類(lèi)位于java.lang包中。
封裝類(lèi)是引用傳遞而基本類(lèi)型是值傳遞
基本類(lèi)型的變量和對(duì)象的引用變量都是在函數(shù)的棧內(nèi)存中分配 ,而實(shí)際的對(duì)象是在存儲(chǔ)堆內(nèi)存中
1.1 基本數(shù)據(jù)類(lèi)型和封裝類(lèi)型的區(qū)別我們來(lái)看下他們之間有哪些區(qū)別:
八種基本數(shù)據(jù)類(lèi)型分別是:byte、char、boolean、int、short、float、double、long;
對(duì)應(yīng)的封裝類(lèi)型分別是:Byte、Character、Boolean、Integer、Short、Float、Double、Long。
基本類(lèi)型 | 封裝類(lèi)型 | 字節(jié)長(zhǎng)度 | 默認(rèn)值 |
---|---|---|---|
boolean | Boolean | 1 | false |
byte | Byte | 1 | 0 |
char | Character | 2 | u0000 |
short | Short | 2 | 0 |
int | integer | 4 | 0 |
long | Long | 8 | 0l或0L |
float | Float | 4 | 0.0f或0.0F |
double | Double | 8 | 0.0 |
在鞏固了上面的基礎(chǔ)知識(shí)點(diǎn)之后,我們?cè)賮?lái)看下另外的一個(gè)知識(shí)點(diǎn) "=="和"equal()" 這兩個(gè)判斷符在比較基本數(shù)據(jù)類(lèi)型和封裝類(lèi)型的時(shí)候會(huì)做的一些事情。
" == ":比較的是基本數(shù)據(jù)類(lèi)型,比較的是它們的值
"equals()": 比較的是引用數(shù)據(jù)類(lèi)型,根據(jù)不同的數(shù)據(jù)類(lèi)型調(diào)用不同的equals方法。在特殊情況下可以重寫(xiě)equals方法。
a==b并不能判斷a等于b,而是判斷是否為同一個(gè)Object。如果我們要判斷他們的值怎么做呢?用equal或者Objects.equals()(JDK1.7之后新加 的語(yǔ)法)
Objects.equals有什么好處呢?
如果用a.equals(b) 如果a是null 的話,還會(huì)拋出空指針異常。但是用Objects.equals就沒(méi)有問(wèn)題。因此我們?cè)谑褂靡妙?lèi)型的時(shí)候需要注意,當(dāng)我們?cè)谫x值的時(shí)候,兩個(gè)變量都是引用同一個(gè)Object。
我們以 int與Integer 作為例子,看下"=="和"equal()"方法:
1)基本型和封裝類(lèi)型進(jìn)行"=="運(yùn)算符的比較,封裝類(lèi)型將會(huì)自動(dòng)拆箱變?yōu)榛拘秃笤龠M(jìn)行比較,因此Integer(0)會(huì)自動(dòng)拆箱為int類(lèi)型再進(jìn)行比較。
2)兩個(gè)Integer類(lèi)型進(jìn)行"=="比較,如果其值在-128至127,那么返回true,否則返回false, 這跟Integer.valueOf()的緩沖對(duì)象有關(guān),后面會(huì)說(shuō)。
3)兩個(gè)封裝類(lèi)型進(jìn)行equals()比較,首先equals()會(huì)比較類(lèi)型,如果類(lèi)型相同,則繼續(xù)比較值,如果值也相同,返回true。
4)基本型封裝類(lèi)型調(diào)用equals(),但是參數(shù)是基本類(lèi)型,這時(shí)候,先會(huì)進(jìn)行自動(dòng)裝箱,基本型轉(zhuǎn)換為其封裝類(lèi)型,再進(jìn)行3中的比較。
3.什么是裝箱和拆箱基本數(shù)據(jù)(Primitive)類(lèi)型的自動(dòng)裝箱(autoboxing)、拆箱(unboxing)是自J2SE 5.0開(kāi)始提供的功能。Java語(yǔ)言規(guī)范中說(shuō)道:在許多情況下包裝與解包裝是由編譯器自行完成的(在這種情況下包裝稱(chēng)為裝箱,解包裝稱(chēng)為拆箱)。
通俗的理解:裝箱:基本類(lèi)型轉(zhuǎn)換成封裝類(lèi)型, 拆箱:封裝類(lèi)型轉(zhuǎn)換成基本類(lèi)型 這么一個(gè)過(guò)程。在上面有介紹八種基本類(lèi)型和對(duì)應(yīng)的封裝類(lèi)型。下面以Integer與int之間的轉(zhuǎn)換作為理解:
Integer a = 2; //Boxing
簡(jiǎn)單的理解:將2裝在一個(gè)箱子里,這個(gè)箱子的類(lèi)型是Integer 。箱子這里面裝的數(shù)值就是2,我們就完成了一次裝箱操作。并把a(bǔ)指向2這個(gè)箱子。
Integer b = new Integer(2);//Boxing
顯示裝箱。生成一個(gè)新的箱子 new Integer(); 并且這個(gè)箱子的值為2.而且讓b指向這個(gè)箱子。
3.2 拆箱(Unboxing)故名思議就是將對(duì)象重新轉(zhuǎn)化為基本數(shù)據(jù)類(lèi)型
int v = a.intValue(); //Unboxing
簡(jiǎn)單的理解:將里面int的值取出來(lái)。拆箱有個(gè)很典型的用法就是在進(jìn)行運(yùn)算的時(shí)候:因?yàn)閷?duì)象時(shí)不能直接進(jìn)行運(yùn)算的,而是要轉(zhuǎn)化為基本數(shù)據(jù)類(lèi)型后才能進(jìn)行加減乘除。
例如:
Integer c = 5; System.out.print(c--);//進(jìn)行計(jì)算時(shí)隱含的有自動(dòng)拆箱4. 裝箱拆箱結(jié)合源碼分析
通過(guò)第四點(diǎn)我們知道裝箱拆箱的基本概念知識(shí),下面我們同樣以Integer 為例,進(jìn)入源碼里面看看里面的乾坤。
我們首先看下Integer的大小。
4.1 Integer 大小可以看出,其定義了Integer的最大值為2^31-1,最小值為-2^31。Integer的基本數(shù)據(jù)類(lèi)型為int。
4.2 Integer中的valueOf()方法再來(lái)看看Integer中的valueOf()方法。
可以看出valueOf()方法是個(gè)靜態(tài)方法。當(dāng)傳進(jìn)來(lái)的變量值在一個(gè)區(qū)間之內(nèi),直接用IntegerCache.cache[]數(shù)組里面的數(shù)返回,否則new一個(gè)新對(duì)象。
接著我們來(lái)看看IntegerCache類(lèi)。其實(shí)也是會(huì)出現(xiàn)坑的一個(gè)地方。
4.3 其中存在的陷阱接著來(lái)說(shuō)下Integer這兒的一個(gè)坑,也是比較有意思的地方。
初始化Integer后,IntegerCache會(huì)緩存[-128,127]之間的數(shù)據(jù),這個(gè)區(qū)間的上限可以配置,取決于java.lang.Integer.IntegerCache.high這個(gè)屬性,這個(gè)屬性在VM參數(shù)里為-XX:AutoBoxCacheMax=2000進(jìn)行設(shè)置調(diào)整或者VM里設(shè)置-Djava.lang.Integer.IntegerCache.high=2000。所以Integer在初始化完成后會(huì)緩存[-128,max]之間的數(shù)據(jù)。cache屬于常量,存放在java的方法區(qū)中。
同樣,在Long,Byte,Short,我們也可以看到緩存,其緩存數(shù)據(jù)長(zhǎng)度均是-128到127。這里不做展開(kāi)。
另外其他陷阱:
如:
System.out.println(Integer.valueOf(null));
Integer對(duì)象的值可以為null,所以編譯器檢查時(shí)不會(huì)出現(xiàn)檢查時(shí)異常,但是在轉(zhuǎn)換成int的時(shí)候就會(huì)拋出空指針異常。
4. 例題分析我們通過(guò)幾個(gè)經(jīng)典的問(wèn)題,來(lái)看看大家到底理解了裝箱與拆箱的知識(shí)點(diǎn)沒(méi)。
new Integer(5) == 5?
new Integer(5) == new Integer(5) ?
Integer.valueOf(5) == Integer.valueOf(5)?
Integer.valueOf(5).intValue() == 5?
new Integer(5).equals(new Integer(5))?
4.1 問(wèn)題一:new Integer(5) == 5?答案:true。 等號(hào)的左邊是一個(gè)Object右邊是一個(gè)數(shù)值,Object和數(shù)值怎么會(huì)相等的呢?Java的編譯器很聰明,它會(huì)自己去做裝箱和拆箱的操作。這邊它將new Integer(5)做的是Unboxing,它會(huì)里面的value取出來(lái),這時(shí)候發(fā)現(xiàn)取出來(lái)的5等于右邊,所以就為true。
4.2 問(wèn)題二:new Integer(5) == new Integer(5) ?答案:false。 new Integer(5) 就是新建一個(gè)箱子,這個(gè)箱子的值就是5。 == 是判斷這兩個(gè)箱子是不是同一個(gè)箱子,不是說(shuō)里面的值是不是一樣.所以是false。因?yàn)樗麄儾皇峭粋€(gè)箱子。
4.3 問(wèn)題三:Integer.valueOf(5) == Integer.valueOf(5)?答案: true。 Integer.valueOf(5)它會(huì)返回一個(gè)箱子給我們,箱子里面的值是5。但是在返回這個(gè)箱子給我們的時(shí)候,可能會(huì)新建一個(gè)新的箱子給我們,也可能會(huì)使用現(xiàn)有的一個(gè)箱子給我們。所以Integer.valueOf(5) == Integer.valueOf(5)。什么情況下才會(huì)相等呢?只有當(dāng)系統(tǒng)已經(jīng)將2這個(gè)箱子建立好了,并且緩存起來(lái)的情況下。會(huì)把箱子的引用同時(shí)發(fā)給等號(hào)的左邊與右邊。這樣的情況,他們才會(huì)互相相等。Integer.valueOf() 是系統(tǒng)給我們分配的一個(gè)箱子,我們發(fā)現(xiàn),每次調(diào)我們的箱子時(shí)候,系統(tǒng)都給了同一個(gè)箱子。這個(gè)我們的 Integer.valueOf(5) == Integer.valueOf(5)
但是: 可能為false。我們?cè)谏厦娼榻B過(guò),在low和high之間,它會(huì)返回一個(gè)系統(tǒng)已經(jīng)生產(chǎn)的cache,否則它會(huì)生產(chǎn)一個(gè)新的出來(lái)??丛创a可以看到low = -128 high = 127。所以當(dāng)它的值超過(guò)了區(qū)間后,它就會(huì)返回新的箱子,所以就會(huì)為false。
我們不用5改用200試一試。
Integer.valueOf(200) == Integer.valueOf(200)
答案:false。 說(shuō)明系統(tǒng)對(duì)小的數(shù)字會(huì)使用系統(tǒng)分配的箱子,對(duì)于大的數(shù)字,系統(tǒng)會(huì)重新new一個(gè)箱子。面試的時(shí)候,可以回答,他們可能相等,也可能不相等。是有系統(tǒng)決定的。
4.4 問(wèn)題四:Integer.valueOf(5).intValue() == 5?答案: true。 intValue()做了一個(gè)拆箱的操作,將里面的值5取出來(lái),值5等于5,所以是true。
4.5 問(wèn)題五:new Integer(5).equals(new Integer(5))?答案:true。 這里我們沒(méi)有用==而是用equals,equals判斷相等是判斷里面的值是不是相等,而不是判斷這個(gè)箱子是不是同一個(gè),所以我們的答案是true。我們來(lái)看看equals的源碼。判斷里面的值是不是相等。
打印結(jié)果: 文末本章節(jié)主要簡(jiǎn)單介紹了自動(dòng)裝箱與拆箱的相關(guān)知識(shí),希望對(duì)大家有所幫助~
今后我會(huì)在每張文章開(kāi)頭增加 每章一點(diǎn)正能量 ,文末增加5個(gè)編程相關(guān)的英語(yǔ)單詞 學(xué)點(diǎn)英語(yǔ)。希望大家和我一樣每天都能積極向上,一起學(xué)習(xí)一同進(jìn)步!
AWT(Abstract Window Toolkit)抽象窗口工具
API(Application Programming Interface)應(yīng)用程序接口
AOP Aspect Oriented Programming(面向切面編程),可以 通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)在不修改源代碼的情況下給程序動(dòng)態(tài)統(tǒng)一 添加功能的一種技術(shù)。
BMP Bean-Managed Persistent(Bean管理的持久性),EJB中由 Bean自己負(fù)責(zé)持久性管理的方法,Bean的內(nèi)容的同步(保存)需要自己編寫(xiě)代碼 實(shí)現(xiàn)。
I18N internationalization(國(guó)際化),這個(gè)單詞的長(zhǎng)度是20,然后取 其首尾字母,中間省略的字母剛好18個(gè)。
歡迎關(guān)注公眾號(hào):Coder編程
獲取最新原創(chuàng)技術(shù)文章和相關(guān)免費(fèi)學(xué)習(xí)資料,隨時(shí)隨地學(xué)習(xí)技術(shù)知識(shí)!
參考文章:
https://blog.csdn.net/u013309...
https://blog.csdn.net/jairusc...
https://www.cnblogs.com/dolph...
推薦閱讀一篇帶你讀懂TCP之“滑動(dòng)窗口”協(xié)議
帶你了解數(shù)據(jù)庫(kù)中JOIN的用法
帶你了解數(shù)據(jù)庫(kù)中g(shù)roup by的用法
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/74332.html
摘要:但是基本數(shù)據(jù)類(lèi)型不是對(duì)象,不具備對(duì)象的特性不攜帶屬性沒(méi)有方法可調(diào)用。自動(dòng)裝箱即直接賦值將會(huì)比使用構(gòu)造方法的方式節(jié)省一塊堆內(nèi)存空間,并自動(dòng)入對(duì)象池。而手動(dòng)裝箱使用構(gòu)造方法會(huì)產(chǎn)生兩塊堆內(nèi)存,而且不會(huì)保存在對(duì)象池中。 概念 java在設(shè)計(jì)之初,有一個(gè)基本原則:一切皆對(duì)象。但是基本數(shù)據(jù)類(lèi)型不是對(duì)象,不具備對(duì)象的特性——不攜帶屬性、沒(méi)有方法可調(diào)用。為了解決此類(lèi)問(wèn)題,Java為每種基本數(shù)據(jù)類(lèi)型分別...
摘要:但其實(shí),虛擬機(jī)并不支持這些語(yǔ)法糖。方式為每個(gè)泛型類(lèi)型創(chuàng)建唯一的字節(jié)碼表示,并且將該泛型類(lèi)型的實(shí)例都映射到這個(gè)唯一的字節(jié)碼表示上。GitHub 2.5k Star 的Java工程師成神之路 ,不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的確定不來(lái)了解一下嗎); 本文從 ...
摘要:但其實(shí),虛擬機(jī)并不支持這些語(yǔ)法糖。方式為每個(gè)泛型類(lèi)型創(chuàng)建唯一的字節(jié)碼表示,并且將該泛型類(lèi)型的實(shí)例都映射到這個(gè)唯一的字節(jié)碼表示上。GitHub 2.5k Star 的Java工程師成神之路 ,不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的確定不來(lái)了解一下嗎); 本文從 ...
摘要:但其實(shí),虛擬機(jī)并不支持這些語(yǔ)法糖。方式為每個(gè)泛型類(lèi)型創(chuàng)建唯一的字節(jié)碼表示,并且將該泛型類(lèi)型的實(shí)例都映射到這個(gè)唯一的字節(jié)碼表示上。GitHub 2.5k Star 的Java工程師成神之路 ,不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的不來(lái)了解一下嗎); GitHub 2.5k Star 的Java工程師成神之路 ,真的確定不來(lái)了解一下嗎); 本文從 ...
摘要:以字符串形式返回指定的請(qǐng)求頭的值。返回一個(gè)數(shù)組,包含客戶(hù)端發(fā)送該請(qǐng)求的所有的對(duì)象。生命的河流就這樣,不舍晝夜,奔向它理想的海洋。 昨天加班 日日刷廢了,這是個(gè)很不好的習(xí)慣補(bǔ)上昨日份的 ========================================================================= 1、下面哪個(gè)不是Java語(yǔ)言的關(guān)鍵字(B) A def...
閱讀 1174·2021-09-22 16:04
閱讀 1552·2019-08-30 15:43
閱讀 1180·2019-08-29 14:01
閱讀 3494·2019-08-26 12:19
閱讀 3411·2019-08-26 12:15
閱讀 1499·2019-08-26 12:13
閱讀 3322·2019-08-23 17:00
閱讀 1554·2019-08-23 15:38