【问题标题】:In Java, does "==" Box or Unbox when comparing an object and a constant value? [duplicate]在Java中,比较对象和常量值时“==”是Box还是Unbox? [复制]
【发布时间】:2020-06-16 14:37:14
【问题描述】:

在比较 Integer 对象和常量值时,Java 是否将值装箱或取消装箱 Integer 对象?

根据我所阅读的内容,“==”是一个引用比较,因此假设 Java 将常量装箱以执行对象之间的引用比较是合乎逻辑的。然而,下面的测试代码似乎给出了矛盾的结果。

Integer v1 = 1000;
Integer v2 = 1000;
boolean b1 = v1 == 1000; //True.
boolean b2 = v1 == v2; //False. Proof that 1000 boxes to new object and is not fetched from cache.

那么使用== 进行对象与常量值比较如何在Java 中工作?这种情况下算子是按值比较的吗?

【问题讨论】:

  • 使用Integer::valueOf(1000)给你一些缓存的机会。
  • IIRC,JLS 默认只需要缓存 256 个值,即从 -128 到 127。此外,Integer v1 = 1000; 在内部调用 value0f 方法。
  • 保证缓存-128到127,但可能缓存更多。如果您使用valueOf,它可能会缓存,也可能不会 - 至少有机会!
  • 我不需要明确使用valueOf 方法。 装箱在内部调用该方法Integer v1 = 1000;Integer v1 = Integer.valueOf(1000); 是一样的,我用调试器就知道了。

标签: java reference equals comparison-operators


【解决方案1】:

所谓的“常量值”是int 字面量,所以它的类型是int

JLS 15.21.1 说:

如果相等运算符的操作数都是数字类型,或者一个是数字类型,而另一个是可转换(第 5.1.8 节)为数字类型,则对操作数执行二进制数字提升。

在您的v1 == 1000 测试中,1000 是数字类型,v1 可以转换为数字类型,因此执行二进制数字提升。

JLS 5.6.2(二进制数字提升)说:

如果任何操作数是引用类型,则对其进行拆箱转换

因此,Integer 操作数 - v1 - 被拆箱为 int 并执行两个 ints 的比较。因此比较的结果是true

当您比较两种引用类型 - v1 == v2 - 不会进行拆箱,仅比较引用,如 JLS 15.21.3 中所述:

如果相等运算符的操作数既是引用类型又是 null 类型,则该操作是对象相等。

由于1000 太大而无法被Integer 缓存,b1b2 引用的不是同一个实例,因此比较的结果是false

【讨论】:

    【解决方案2】:

    整数池与字符串池相同,但如果整数对象在 -128 到 127 范围内,它会缓存值 因此,当您尝试将此 range 中的值分配给包装对象时,boxing 操作将调用 Integer.valueOf 方法并依次调用它将分配对已在池中的对象的引用

    但是,如果您将这个 范围 之外的值分配给包装器 reference 类型,Integer.valueOf 将创建一个新的该值的整数对象。因此,比较具有超出此范围的值的 Integer 对象的引用将给您错误

    所以你的情况

    Integer v1 = 1000;
    Integer v2 = 1000;
    boolean b1 = v1 == 1000; //True.
    boolean b2 = v1 == v2; // out of range so it will false but if you use 127 instead of 1000 then it will true.
    

    查看文档here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-12
      • 2019-10-16
      • 2012-09-15
      • 1970-01-01
      • 2010-11-09
      • 2019-01-07
      • 1970-01-01
      • 2019-12-23
      相关资源
      最近更新 更多