用於比較原始包裝物件(如 Integer)的陷阱

(這個陷阱同樣適用於所有原始包裝型別,但我們將為 Integerint 進行說明。)

使用 Integer 物件時,很有可能使用 == 來比較值,因為這是你對 int 值所做的。在某些情況下,這似乎有效:

Integer int1_1 = Integer.valueOf("1");
Integer int1_2 = Integer.valueOf(1);

System.out.println("int1_1 == int1_2: " + (int1_1 == int1_2));          // true
System.out.println("int1_1 equals int1_2: " + int1_1.equals(int1_2));   // true

在這裡,我們建立了兩個 Integer 物件,其值為 1 並進行比較(在本例中,我們建立了一個來自 String,另一個來自 int 文字。還有其他選擇)。此外,我們觀察到兩種比較方法(==equals)都產生了 true

當我們選擇不同的值時,此行為會更改:

Integer int2_1 = Integer.valueOf("1000");
Integer int2_2 = Integer.valueOf(1000);

System.out.println("int2_1 == int2_2: " + (int2_1 == int2_2));          // false
System.out.println("int2_1 equals int2_2: " + int2_1.equals(int2_2));   // true

在這種情況下,只有 equals 比較產生正確的結果。

這種行為差異的原因是,JVM 維護了 -128 到 127 範圍內的 Integer 物件的快取。(可以使用系統屬性“java.lang.Integer.IntegerCache.high”覆蓋上限值或者 JVM 引數“-XX:AutoBoxCacheMax = size”)。對於此範圍內的值,Integer.valueOf() 將返回快取值,而不是建立新值。

因此,在第一個示例中,Integer.valueOf(1)Integer.valueOf("1") 呼叫返回了相同的快取 Integer 例項。相比之下,在第二個例子中,Integer.valueOf(1000)Integer.valueOf("1000") 都建立並返回了新的 Integer 物件。

參考型別的 == 運算子測試引用相等性(即同一物件)。因此,在第一個例子中,int1_1 == int1_2true,因為引用是相同的。在第二個例子中,int2_1 == int2_2 是假的,因為引用是不同的。