Java:整数等于 vs. ==
Posted
技术标签:
【中文标题】Java:整数等于 vs. ==【英文标题】:Java: Integer equals vs. == 【发布时间】:2011-04-07 23:11:21 【问题描述】:从 Java 1.5 开始,Integer
与 int
在许多情况下几乎可以互换。
但是,我发现我的代码中有一个潜在的缺陷,这让我有点吃惊。
以下代码:
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 ) ..
第二个将被自动拆箱(当然你必须先检查null
s)。
【讨论】:
以上是关于Java:整数等于 vs. ==的主要内容,如果未能解决你的问题,请参考以下文章