原始類型自動(dòng)拆裝箱問題
[TOC]
起因
近期在工作中驼仪,發(fā)現(xiàn)好多代碼都錯(cuò)誤使用了數(shù)值封裝類型的方法酸钦,本無需主動(dòng)拆箱的赞赖,使用了拆箱方法等异袄,對(duì)自動(dòng)拆裝箱不熟導(dǎo)致的編碼的問題通砍,所以才寫了這篇文章。
數(shù)值操作符
Operator | never unboxing | auto unboxing |
---|---|---|
== | Y | N |
!= | Y | N |
>= | N | Y |
<= | N | Y |
+ | N | Y |
- | N | Y |
* | N | Y |
/ | N | Y |
PS: 如果一方為原始類型烤蜕,則以上所有操作符都會(huì)自動(dòng)拆箱.如果封裝類型為null封孙,自動(dòng)拆箱會(huì)報(bào)NPE的錯(cuò)誤,因?yàn)槭钦{(diào)用intValue函數(shù)實(shí)現(xiàn)的自動(dòng)拆箱讽营。
為什么==和!=不會(huì)自動(dòng)拆箱
這個(gè)是由jvm底層實(shí)現(xiàn)決定的虎忌,因?yàn)樵趈vm中==
跟!=
的實(shí)現(xiàn)是對(duì)象通用的比較符,而Integer
等封裝類型也屬于對(duì)象橱鹏,會(huì)在堆中分配內(nèi)存膜蠢,而這兩個(gè)操作符是直接比較的是對(duì)象在內(nèi)存中是否為同一塊內(nèi)存地址,也可以理解為c或者c++中的指針比較莉兰,如果不是同一個(gè)內(nèi)存地址挑围,那么==
和!=
會(huì)相應(yīng)返回對(duì)應(yīng)的false和true。
那為什么在默認(rèn)環(huán)境中糖荒,在[-128,127]
范圍內(nèi)杉辙,封裝類型比較值會(huì)返回正確的答案?
比如如下的代碼:
@Test
public void imageIoTest() throws Exception {
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true
a = new Integer(127);
b = 127;
System.out.println(a == b); // false
a = 128;
b = 128;
System.out.println(a == b); // false
}
這是因?yàn)閖dk中捶朵,自動(dòng)裝箱調(diào)用了各類型的#valueOf(int)
方法蜘矢,在里面可以看到,在[-128,127]
的范圍(Integer除外)內(nèi)泉孩,都會(huì)去一個(gè)cache的數(shù)組中取值硼端,jdk在jvm啟動(dòng)的時(shí)候就將[-128,127]
的封裝類型(僅限于Integer、Long寓搬、Short珍昨、Byte)的對(duì)象緩存起來了,默認(rèn)緩存[-128,127]
的值句喷,其中Byte緩存了所有的值镣典,也就是說Byte類型直接使用==
和!=
號(hào)也可以得出正確的數(shù)值(只要你不是自己new出來的Byte對(duì)象)。但如果是自行new出來的對(duì)象唾琼,就無法得出正確的數(shù)值了兄春,這是因?yàn)閚ew相當(dāng)于新開辟了一塊內(nèi)存存儲(chǔ)相應(yīng)的數(shù)值了,內(nèi)存地址都不一樣了锡溯。
Integer的特殊性
其中Integer類型又是比較特殊的赶舆,它可以通過-XX:AutoBoxCacheMax=1024
和-Djava.lang.Integer.IntegerCache.high=1024
的方式配置緩存的最大值哑姚,注意,該配置只能配置最大值芜茵,最小值目前都是-128
(目前jdk最高版本是JDK17叙量,后面會(huì)不會(huì)也允許配置,不得而知九串,可能性比較低)绞佩,最大值范圍為[127,Integer.MAX_VALUE - -128 -1]
,因?yàn)槭褂玫氖菙?shù)組的方式做緩存猪钮,因此不能超過數(shù)組允許的最大下標(biāo)值Integer.MAX_VALUE
品山,而又要有128+1個(gè)位置來存儲(chǔ)[-128,0]
,因此最大的緩存值為Integer.MAX_VALUE- -128 -1
烤低。
無論怎么來說肘交,封裝類型的比較還是比較建議使用equals來進(jìn)行等值比較的。
通常來(Since JDK1.7)拂玻,可以用Objects.equal(one,otherOne)來比較兩個(gè)數(shù)字酸些,可以更加優(yōu)雅地避免空指針的問題,如果比較封裝類型的數(shù)值檐蚜,建議使用該方法魄懂,代碼看起來更加整潔。