Java:整数等于 vs. ==

Posted

技术标签:

【中文标题】Java:整数等于 vs. ==【英文标题】:Java: Integer equals vs. == 【发布时间】:2011-04-07 23:11:21 【问题描述】:

从 Java 1.5 开始,Integerint 在许多情况下几乎可以互换。

但是,我发现我的代码中有一个潜在的缺陷,这让我有点吃惊。

以下代码:

Integer cdiCt = ...;
Integer cdsCt = ...;
...
if (cdiCt != null && cdsCt != null && cdiCt != cdsCt)
    mismatch = true;

当值相等时,似乎错误地设置了不匹配,尽管我无法确定在什么情况下。我在 Eclipse 中设置了一个断点,发现 Integer 的值都是 137,我检查了布尔表达式,它说它是错误的,但是当我越过它时,它会将不匹配设置为 true。

将条件更改为:

if (cdiCt != null && cdsCt != null && !cdiCt.equals(cdsCt))

解决了问题。

谁能解释一下为什么会这样?到目前为止,我只在我自己的 PC 上的本地主机上看到了这种行为。在这种特殊情况下,代码成功通过了大约 20 次比较,但在 2 次比较失败。问题始终可以重现。

如果这是一个普遍存在的问题,它应该会在我们的其他环境(开发和测试)上导致错误,但到目前为止,在执行此代码 sn-p 的数百次测试之后,没有人报告此问题。

使用== 比较两个Integer 值仍然不合法吗?

除了下面所有的好答案之外,下面的 *** 链接还有很多额外的信息。它实际上会回答我原来的问题,但是因为我没有在我的问题中提到自动装箱,所以它没有出现在选定的建议中:

Why can't the compiler/JVM just make autoboxing “just work”?

【问题讨论】:

【参考方案1】:

问题在于您的两个 Integer 对象就是这样的对象。它们不匹配,因为您正在比较两个对象引用,而不是其中的值。显然.equals 被覆盖以提供值比较而不是对象引用比较。

【讨论】:

很好的答案,但它没有解释为什么它只对 137 失败。【参考方案2】:

Integer 指的是引用,也就是说,在比较引用时,您要比较的是它们是否指向同一个对象,而不是值。因此,您看到的问题。它与普通的int 类型一起工作的原因是它取消了Integer 包含的值。

我可以补充一下,如果你正在做你正在做的事情,为什么要以 if 语句开头?

mismatch = ( cdiCt != null && cdsCt != null && !cdiCt.equals( cdsCt ) );

【讨论】:

【参考方案3】:

JVM 正在缓存整数值。因此,与 == 的比较仅适用于 -128 到 127 之间的数字。

参考:#Immutable_Objects_.2F_Wrapper_Class_Caching

【讨论】:

谢谢,这确实解释了 137 失败的原因!它还回答了我关于为什么它不是一个普遍问题的问题,在我将遇到的 95% 的情况下,该值将低于 127。现在很高兴能抓住这一点,尽管对于不是的 5% 来说。 有趣的旁注:直到几周前,cdiCt 和 cdsCt 都是整数,所以这很好,但我必须将它们设为整数,以便检查处理方式不同的 null 情况。 .. @Jeremy 是的,这是一个非常模糊的问题,但作为一般规则,您使用 .equals() 对象和 == 原语。您不能依赖自动拆箱来进行相等性测试。 大声笑,然后复选标记给你!看来科林已经有足够的积分了。 请注意 new Integer(1) != new Integer(1) 也是如此。 new 总是返回一个新地址。自动装箱使用缓存版本。返回整数的其他方式(不更新它们)也可能返回缓存值。【参考方案4】:

您无法将两个Integer 与一个简单的== 进行比较,它们是对象,因此大多数时候引用不会相同。

有一个技巧,Integer 介于 -128 和 127 之间,引用将与自动装箱使用 Integer.valueOf() 缓存小整数相同。

如果被装箱的值 p 是 true、false、一个字节、一个在 \u0000 到 \u007f 范围内的字符,或者一个介于 -128 和 127 之间的 int 或短数字,那么让 r1 和 r2 是任何p的两次拳击转换。 r1 == r2 总是如此。


资源:

JLS - Boxing

关于同一主题:

autoboxing vs manual boxing java

【讨论】:

是来自 JLS 的保证还是仅针对 Oracle JVM? 引用部分来自JLS,所以是JLS的保证 回复:保证。我还是不会太依赖它。 new Integer(1) == new Integer(1) 仍然是假的。 @Thilo new ... == new ... 始终是 false @Thilo 没错,在处理对象时总是使用equals()。这应该是学习 Java 时应该知道的第一件事。顺便说一句,我猜Integer 的构造函数是私有的,即实例总是通过valueOf() 方法创建的。但我看到构造函数是公开的。【参考方案5】:

"==" 总是比较值的内存位置或对象引用。 equals 方法总是比较值。但 equals 也间接使用“==”运算符来比较值。

Integer 使用 Integer 缓存来存储从 -128 到 +127 的值。如果 == 运算符用于检查 -128 到 127 之间的任何值,则返回 true。除了这些值,它返回 false 。

请参阅 link 了解更多信息

【讨论】:

【参考方案6】:

除了这些给出的很好的答案,我学到的是:

切勿使用 == 比较对象,除非您打算比较它们 通过他们的参考。

【讨论】:

那是因为== 或多或少比较堆栈上的值。因此,对于原语,它是它们的值,对于对象,它是它们的引用(哈希码)。 .equals 比较在相应类的覆盖方法中定义的任何内容。请注意,如果没有覆盖,Object 中的默认 .equals 会执行以下操作:return (this == obj);【参考方案7】:

为了正确使用==,您可以在进行== 比较之前将比较的Integer 值之一拆箱,例如:

if ( firstInteger.intValue() == secondInteger ) ..

第二个将被自动拆箱(当然你必须先检查nulls)。

【讨论】:

以上是关于Java:整数等于 vs. ==的主要内容,如果未能解决你的问题,请参考以下文章

大于等于0的正整数正则表达式是啥?

HDU2092 整数解暴力+韦达定理

显示大于等于整数的2的最小幂的代码

java math.floor是啥意思

java-运算符

java编程序题目是随机生成0到10以内的整数十个,要求随机产生的 10个数中,等于7,8,9,10的数不超过3个