为了账号安全,请及时绑定邮箱和手机立即绑定

在比较 Java 中的两个基元和两个对象时,== 实际上工作相同还是不同?

在比较 Java 中的两个基元和两个对象时,== 实际上工作相同还是不同?

斯蒂芬大帝 2023-06-14 10:26:25
在寻找==Java 中逻辑等于如何工作的解释时,答案总是类似于:对于图元,它返回图元是否具有相同的值(这包括将图元与其 WrapperObject 进行比较,因为 WrapperObject 会自动拆箱为图元)。对于对象,它返回它们是否代表堆上的同一个对象。但这些解释似乎都暗示这是两种不同的东西,它们的==行为不同取决于你是在比较对象还是基元。在我看来,它们实际上必须是完全相同的东西:从 Stack 中取出两个变量并比较它们的值。改变的不是 的行为==,而是它所比较的值所代表的内容。如果你比较的东西是原语,那么 Stack 上的值就是原语本身的值。如果您正在比较对象,那么堆栈上的值就是引用的值(因此是对象在堆上的地址)。我是不是误解了什么,或者==在所有情况下都表现得一样?如果你能给我指出这在幕后是如何工作的文档,那就加分了。
查看完整描述

2 回答

?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

在 Java 语言级别,==运算符语义以独立于实现的方式指定(在JLS 15.21中)。严格来说,您不能从 JLS 文本中推断出“幕后”实现细节。您只能说,任何符合规范的实现都==必须以某种方式运行。

我假设我们正在谈论传统的 JVM,其中引用的实际机器表示是机器地址。可以通过其他方式实现引用;例如,使用某种间接寻址机制,例如PIDLAM。

在字节码级别,有许多不同的==字节码指令实现了依赖于类型(int,或引用)的逻辑long。但是,比较的语义是相似的。一旦字节码被验证为类型安全的,为了在硬件级别进行比较,就可以对整数和地址进行相同的处理。==

在硬件(机器指令)级别,==原始整数类型和非原始值的工作方式相同。在这两种情况下,它将执行一条机器指令,该指令比较从寄存器或内存(堆或堆栈)中获取的两个“字”。


JLS 指定的==forfloat和的语义double有点不同,因为特殊值(无穷大和非数字值)需要特殊处理。例如:NaN == NaN 是false. 另请参阅 IEEE 754 浮点标准。

为此有不同的字节码,并且在硬件级别使用的指令与整数和参考案例中使用的指令不同。(特殊值的处理通常在浮动硬件中处理。)


JLS 指定了==for boolean、和 is的语义byte,以便在比较它们之前将值提升为另一种类型(、或) 。如果操作数具有不同的(未装箱的)类型,则提升也会发生在其他情况下。 shortcharintlongfloatdouble

此外,如果一个(但不是两个!)操作数被装箱,则会发生拆箱。如果两个操作数都被装箱,则为==引用比较。


总结以上...

我是不是误解了什么,或者 == 实际上在所有情况下都表现得一样?

不,如果您包括浮点类型,以及原始加宽和拆箱的注意事项,则不会。

如果你能给我指出这在幕后是如何工作的文档,那就加分了。

没有关于此的官方(Oracle)公共文档。JLS 和 JVM 规范没有规定实现策略。


查看完整回答
反对 回复 2023-06-14
?
Helenr

TA贡献1780条经验 获得超3个赞

我理解你的解释,并且给出某些术语的定义是正确的。但它不符合 Java 谈论对象和原语的方式。

在 Java 中“引用”对象的想法被严重低估了;我认为有可能成为一名“Java 程序员”却并不真正了解什么是引用。您可以记住它产生影响的规则——“==”运算符,将参数传递给方法——而不理解它是如何实现的,或者可能是如何实现的。

所以我认为许多使用 Java 编程的人会感到困惑,因为说 == “在所有情况下都表现相同”,因为这涉及太多“幕后”知识。Java 不鼓励您(或要求您)在那种程度上“深入了解”。


查看完整回答
反对 回复 2023-06-14
  • 2 回答
  • 0 关注
  • 102 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信