用于比较原始包装对象(如 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 是假的,因为引用是不同的。