Java中“100=100”為True,而"1000=1000"為False?
前言
今天跟大家聊一個有趣的話題,在Java中兩個Integer對象做比較時,會產(chǎn)生意想不到的結(jié)果。
例如:
Integer a = 100;
Integer b = 100;
System.out.println(a==b);
其運(yùn)行結(jié)果是:true。
而如果改成下面這樣:
Integer a = 1000;
Integer b = 1000;
System.out.println(a==b);
其運(yùn)行結(jié)果是:false。
看到這里,懵了沒有?
為什么會產(chǎn)生這樣的結(jié)果呢?
1、Integer對象
上面例子中的a和b,是兩個Integer對象。
而非Java中的8種基本類型。
8種基本類型包括:
- byte
- short
- int
- long
- float
- double
- boolean
- char
Integer其實(shí)是int的包裝類型。
在Java中,除了上面的這8種類型,其他的類型都是對象,保存的是引用,而非數(shù)據(jù)本身。
Integer a = 1000;
Integer b = 1000;
可能有些人認(rèn)為是下面的簡寫:
Integer a = new Integer(1000);
Integer b = new Integer(1000);
這個想法表面上看起來是對的,但實(shí)際上有問題。
在JVM中的內(nèi)存分布情況是下面這樣的:
在棧中創(chuàng)建了兩個局部變量a和b,同時在堆上new了兩塊內(nèi)存區(qū)域,他們存放的值都是1000。
變量a的引用指向第一個1000的地址。
而變量b的引用指向第二個1000的地址。
很顯然變量a和b的引用不相等。
既然兩個Integer對象用==號,比較的是引用是否相等,但下面的這個例子為什么又會返回true呢?
Integer a = 100;
Integer b = 100;
System.out.println(a==b);
不應(yīng)該也返回false嗎?
對象a和b的引用不一樣。
Integer a = 1000;
Integer b = 1000;
其實(shí)正確的簡寫是下面這樣的:
Integer a = Integer.valueOf(1000);
Integer b = Integer.valueOf(1000);
在定義對象a和b時,Java自動調(diào)用了Integer.valueOf將數(shù)字封裝成對象。
而如果數(shù)字在low和high之間的話,是直接從IntegerCache緩存中獲取的數(shù)據(jù)。
Integer類的內(nèi)部,將-128~127之間的數(shù)字緩存起來了。
也就是說,如果數(shù)字在-128~127,是直接從緩存中獲取的Integer對象。如果數(shù)字超過了這個范圍,則是new出來的新對象。
文章示例中的1000,超出了-128~127的范圍,所以對象a和b的引用指向了兩個不同的地址。
而示例中的100,在-128~127的范圍內(nèi),對象a和b的引用指向了同一個地址。
所以會產(chǎn)生文章開頭的運(yùn)行結(jié)果。
為什么Integer類會加這個緩存呢?
答:-128~127是使用最頻繁的數(shù)字,如果不做緩存,會在內(nèi)存中產(chǎn)生大量指向相同數(shù)據(jù)的對象,有點(diǎn)浪費(fèi)內(nèi)存空間。
Integer a = 1000;
Integer b = 1000;
如果想要上面的對象a和b相等,我們該怎么判斷呢?
2、判斷相等
在Java中,如果使用==
號比較兩個對象是否相等,比如:a==b,其實(shí)比較的是兩個對象的引用是否相等。
很顯然變量a和b的引用,指向的是兩個不同的地址,引用肯定是不相等的。
因此下面的執(zhí)行結(jié)果是:false。
Integer a = Integer.valueOf(1000);
Integer b = Integer.valueOf(1000);
System.out.println(a==b);
由于1000在Integer緩存的范圍之外,因此上面的代碼最終會變成這樣:
Integer a = new Integer(1000);
Integer b = new Integer(1000);
System.out.println(a==b);
如果想要a和b比較時返回true,該怎么辦呢?
答:調(diào)用equals方法。
代碼改成這樣的:
Integer a = Integer.valueOf(1000);
Integer b = Integer.valueOf(1000);
System.out.println(a.equals(b));
執(zhí)行結(jié)果是:true。
其實(shí)equals方法是Object類的方法,所有對象都有這個方法。
它的底層也是用的==號判斷兩個Object類型的對象是否相等。
不過Integer類對該方法進(jìn)行了重寫:
它的底層會先調(diào)用Integer類的intValue方法獲取int類型的數(shù)據(jù),然后再通過==號進(jìn)行比較。
此時,比較的不是兩個對象的引用是否相等,而且比較的具體的數(shù)據(jù)是否相等。
我們使用equals方法,可以判斷兩個Integer對象的值是否相等,而不是判斷引用是否相等。
總結(jié)
Integer類中有緩存,范圍是:-128~127。
Integer a = 1000;
其實(shí)默認(rèn)調(diào)用了Integer.valueOf方法,將數(shù)字轉(zhuǎn)換成Integer類型:
Integer a = Integer.valueOf(1000);
如果數(shù)字在-128~127之間,則直接從緩存中獲取Integer對象。
如果數(shù)字在-128~127之外,則該方法會new一個新的Integer對象。
我們在判斷兩個對象是否相等時,一定要多注意:
- 判斷兩個對象的引用是否相等,用==號判斷。
- 判斷兩個對象的值是否相等,調(diào)用equals方法判斷。