【问题标题】:Comparing Character, Integer and similar types in Java: Use equals or ==?比较 Java 中的字符、整数和类似类型:使用等于还是 ==?
【发布时间】:2009-04-09 20:32:14
【问题描述】:

我想确认一下 Java 中的一些东西: 如果我有一个字符、整数或长整数之类的东西,我应该使用 equals 还是 == 就足够了?

我知道字符串不能保证每个唯一字符串只有一个实例,但我不确定其他盒装类型。

我的直觉是使用 equals,但我想确保我没有浪费性能。

【问题讨论】:

  • 永远不要假设任何关于性能的事情 - 测试它。也许 == 和 .equals 的性能差不多,在这种情况下问题没有实际意义。
  • 关于性能的唯一假设:不正确的代码是否更快并不重要。 :-)
  • 这就是我想要确定的。
  • 至于 “我知道对于字符串,不能保证每个唯一字符串只有一个实例”:如果出于某种原因您需要它,见String#intern()

标签: java equals primitive


【解决方案1】:

编辑:规范为装箱转换提供一些保证。来自section 5.1.7

如果被装箱的值p为真, false,一个字节,一个字符在范围内 \u0000 到 \u007f,或者一个 int 或 short 介于 -128 和 127 之间的数字,然后让 r1 和 r2 是任意两个的结果 p的拳击转换。它总是 r1 == r2 的情况。

请注意,实现可以使用更大的池。

我会真的避免编写依赖于此的代码。不是因为它可能会失败,而是因为它并不明显——很少有人会那么了解规范。 (我以前认为它是依赖于实现的。)

您应该使用equals 或比较基础值,即

if (foo.equals(bar))

if (foo.intValue() == bar.intValue())

请注意,即使保证自动装箱使用固定值,其他调用方也始终可以创建单独的实例。

【讨论】:

  • IIRC,JLS 表示 byte、short 和 int 至少为 -128 到 127,char 等效于枯萎,但 long、float 或 short 则没有。 IIRC、6u14 和以前的性能版本允许通过系统属性配置池大小。
  • 哇,你说得对。我可以发誓它给游泳池或不游泳池留有余地。将编辑。
  • @Tom 你两次提到short。实际上,空头和多头都有一个大小相同的池。你可以说布尔值总是被合并的。
【解决方案2】:

如果您想比较任何对象的值,请使用.equals()

即使(尤其是)这些对象是原始包装类型 Byte、Character、Short、Integer、Long、Float、Double 和 Boolean。

"==" 只会比较对象的身份,而你这很少是你想要的。事实上,原始包装器永远不会满足您的需求。

仅在这两种情况之一中使用==

  1. 比较中涉及的所有值都是原始类型(最好不是浮点数)
  2. 你真的想知道两个引用是否指向同一个对象(这包括比较enums,因为那里的值绑定到对象标识)

【讨论】:

  • 场景 3:您正在比较枚举实例或其他以允许 == 安全的方式管理其实例的不可变类型。
  • 你的场景3和场景2一样
  • @TofuBeer:从技术上讲,是的,但很多人不会这么想。
【解决方案3】:

Java Language Spec 5.1.7:

如果被装箱的值p为真, false,一个字节,一个字符在范围内 \u0000 到 \u007f,或者一个 int 或 short 介于 -128 和 127 之间的数字,然后让 r1 和 r2 是任意两个的结果 p的拳击转换。它总是 r1 == r2 的情况。

和:

讨论

理想情况下,装箱给定的原语 值 p,总是会产生 相同的参考。在实践中,这 使用现有的可能不可行 实施技术。规则 以上是务实的妥协。这 上面的最后条款要求 某些共同的价值观总是被装箱 变成无法区分的物体。这 实现可能会懒惰地缓存这些 或急切地。

对于其他值,此公式 不允许任何关于 盒装值的标识 程序员的一部分。这将允许 (但不要求)分享一些或 所有这些参考资料。

这可确保在最常见的 情况下,行为将是 想要的,而不是施加不适当的 性能损失,尤其是在 小型设备。更少的内存限制 例如,实现可能 缓存所有字符和短裤,如 以及整数和长整数 范围为 -32K - +32K。

因此,在某些情况下 == 会起作用,而在许多其他情况下则不会。始终使用 .equals 以确保安全,因为您无法(通常)授予实例的获取方式。

如果速度是一个因素(大多数 .equals 以 == 比较开头,或者至少应该这样)并且您可以保证它们是如何分配的并且它们符合上述范围,那么 == 是安全的。

某些 VM 可能会增加该大小,但假设语言规范指定的最小大小比依赖特定 VM 行为更安全,除非您确实确实需要这样做。

【讨论】:

    【解决方案4】:
    //Quick test
    public class Test {
      public static void main(String[] args) {
        System.out.println("Are they equal? "+ (new Long(5) == new Long(5)));
      }
    }
    

    输出:

    “他们相等吗?0”

    答案:

    不,它们不相等。您必须使用 .equals 或比较它们的原始值。

    【讨论】:

    • Long.valueOf(5) == Long.valueOf(5) 怎么样?
    • new Long(...) 每次都会给你一个不同的参考。那里并不奇怪。然而 Long.valueOf(...) 将汇集引用。就像莫里斯说的那样,你的测试在那种情况下不是正确的。
    • 由于您可能不知道 Long 是如何获得的,因此使用 == 几乎永远不会安全。
    • 确实,TofuBeer 是正确的。肯定有办法获得两个实际上相同的多头,特别是正如他在回答中指出的那样。依赖这些方式仍然是一个糟糕的主意,因为如果您稍后更改这些 Long,您不会考虑比较它们是否相等的方式也发生了变化。
    • CaptainAwesomePants 只需要显示一个 == 失败的实例,以证明您不能普遍依赖 ==,即使在某些情况下它恰好起作用。
    【解决方案5】:

    equals(Object o) 方法的实现几乎总是以

    if(this == o) return true;
    

    所以即使== 为真,使用equals 也不会对性能造成太大影响。

    我建议总是*对对象使用 equals 方法。

    * 当然,在极少数情况下你不应该接受这个建议。

    【讨论】:

      【解决方案6】:

      一般的答案是,你不能保证对于相同的数值,你得到的 Long 对象是相同的(即使你限制自己使用 Long.valueOf())。

      但是,通过首先尝试测试引用的相等性(使用 ==),然后如果失败,尝试 equals(),您可能会获得性能改进。这一切都取决于额外 == 测试和方法调用的比较成本...您的里程可能会有所不同,但值得尝试一个简单的循环测试,看看哪个更好。

      【讨论】:

        【解决方案7】:

        值得注意的是,自动装箱的值将使用池化对象(如果它们可用)。这就是为什么 (Integer) 0 == (Integer) 0 但是 (Integer) 128 != (Integer) 128 for Java 6u13

        【讨论】:

          【解决方案8】:

          我喜欢直观地看到结果:

            public static void main(String[] args)
            {
                  Integer a = 126; //no boxed up conversion, new object ref
                  Integer b = 126; //no boxed up conversion, re-use memory address
                  System.out.println("Are they equal? " + (a == b)); // true
                  Integer a1 = 140; //boxed up conversion, new object
                  Integer b1 = 140; //boxed up conversion, new object
                  System.out.println("Are they equal? " + (a1 == b1)); // false
                  System.out.println("Are they equal? " + (new Long(5) == new Long(5))); // false
            }
          

          【讨论】:

            【解决方案9】:

            == 比较对象引用,而equals(Object obj) 比较对象是否相等。 如果存在多个相等对象的实例,那么您必须使用equals 进行相等比较。

            例子:

            Integer i1 = new Integer(12345);
            Integer i2 = new Integer(12345);
            

            这些是不同的对象实例,但是根据 Integer 的相等性是相等的,所以你必须使用equals(Object obj)

            public enum Gender {
                MALE, FEMALE;
            }
            

            在这种情况下,只有一个 FEMALE 实例存在,因此 == 可以安全使用。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2023-04-09
              • 2022-06-30
              • 1970-01-01
              • 1970-01-01
              • 2011-09-03
              • 2011-11-29
              • 2021-06-27
              • 1970-01-01
              相关资源
              最近更新 更多