Java中“100=100”為true,而"1000=1000"為false?

ITPUB社群發表於2023-12-22


來源:蘇三說技術

前言

今天跟大家聊一個有趣的話題,在Java中兩個Integer物件做比較時,會產生意想不到的結果。

例如:

Integer a = 100;
Integer b = 100;
System.out.println(a==b);

其執行結果是:true。

而如果改成下面這樣:

Integer a = 1000;
Integer b = 1000;
System.out.println(a==b);

其執行結果是:false。

看到這裡,懵了沒有?

為什麼會產生這樣的結果呢?

1 Integer物件

上面例子中的a和b,是兩個Integer物件。

而非Java中的8種基本型別。

8種基本型別包括:

  • byte
  • short
  • int
  • long
  • float
  • double
  • boolean
  • char

Integer其實是int的包裝型別。

在Java中,除了上面的這8種型別,其他的型別都是物件,儲存的是引用,而非資料本身。

Integer a = 1000;
Integer b = 1000;

可能有些人認為是下面的簡寫:

Integer a = new Integer(1000);
Integer b = new Integer(1000);

這個想法表面上看起來是對的,但實際上有問題。

在JVM中的記憶體分佈情況是下面這樣的:Java中“100=100”為true,而"1000=1000"為false?在棧中建立了兩個區域性變數a和b,同時在堆上new了兩塊記憶體區域,他們存放的值都是1000。

變數a的引用指向第一個1000的地址。

而變數b的引用指向第二個1000的地址。

很顯然變數a和b的引用不相等。

既然兩個Integer物件用==號,比較的是引用是否相等,但下面的這個例子為什麼又會返回true呢?

Integer a = 100;
Integer b = 100;
System.out.println(a==b);

不應該也返回false嗎?

物件a和b的引用不一樣。

Integer a = 1000;
Integer b = 1000;

其實正確的簡寫是下面這樣的:

Integer a = Integer.valueOf(1000);
Integer b = Integer.valueOf(1000);

在定義物件a和b時,Java自動呼叫了Integer.valueOf將數字封裝成物件。Java中“100=100”為true,而"1000=1000"為false?而如果數字在low和high之間的話,是直接從IntegerCache快取中獲取的資料。

Java中“100=100”為true,而"1000=1000"為false?Integer類的內部,將-128~127之間的數字快取起來了。

也就是說,如果數字在-128~127,是直接從快取中獲取的Integer物件。如果數字超過了這個範圍,則是new出來的新物件。

文章示例中的1000,超出了-128~127的範圍,所以物件a和b的引用指向了兩個不同的地址。

而示例中的100,在-128~127的範圍內,物件a和b的引用指向了同一個地址。

所以會產生文章開頭的執行結果。

為什麼Integer類會加這個快取呢?

答:-128~127是使用最頻繁的數字,如果不做快取,會在記憶體中產生大量指向相同資料的物件,有點浪費記憶體空間。

Integer a = 1000;
Integer b = 1000;

如果想要上面的物件a和b相等,我們該怎麼判斷呢?

2 判斷相等

在Java中,如果使用==號比較兩個物件是否相等,比如:a==b,其實比較的是兩個物件的引用是否相等。

很顯然變數a和b的引用,指向的是兩個不同的地址,引用肯定是不相等的。

因此下面的執行結果是: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,該怎麼辦呢?

答:呼叫equals方法。

程式碼改成這樣的:

Integer a = Integer.valueOf(1000);
Integer b = Integer.valueOf(1000);
System.out.println(a.equals(b));

執行結果是:true。

其實equals方法是Object類的方法,所有物件都有這個方法。Java中“100=100”為true,而"1000=1000"為false?它的底層也是用的==號判斷兩個Object型別的物件是否相等。

不過Integer類對該方法進行了重寫:Java中“100=100”為true,而"1000=1000"為false?它的底層會先呼叫Integer類的intValue方法獲取int型別的資料,然後再透過==號進行比較。

此時,比較的不是兩個物件的引用是否相等,而且比較的具體的資料是否相等。

我們使用equals方法,可以判斷兩個Integer物件的值是否相等,而不是判斷引用是否相等。

總結

Integer類中有快取,範圍是:-128~127

Integer a = 1000;

其實預設呼叫了Integer.valueOf方法,將數字轉換成Integer型別:

Integer a = Integer.valueOf(1000);

如果數字在-128~127之間,則直接從快取中獲取Integer物件。

如果數字在-128~127之外,則該方法會new一個新的Integer物件。

我們在判斷兩個物件是否相等時,一定要多注意:

  1. 判斷兩個物件的引用是否相等,用==號判斷。
  2. 判斷兩個物件的值是否相等,呼叫equals方法判斷。 


來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70024420/viewspace-3001171/,如需轉載,請註明出處,否則將追究法律責任。

相關文章