用于比较原始包装对象(如 Integer)的陷阱
(这个陷阱同样适用于所有原始包装类型,但我们将为 Integer
和 int
进行说明。)
使用 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_2
是 true
,因为引用是相同的。在第二个例子中,int2_1 == int2_2
是假的,因为引用是不同的。