【问题标题】:How to compare two java objects [duplicate]如何比较两个java对象[重复]
【发布时间】:2013-04-10 18:00:48
【问题描述】:

我有两个从同一个类实例化的 java 对象。

MyClass myClass1 = new MyClass();
MyClass myClass2 = new MyClass();

如果我将它们的两个属性都设置为完全相同的值,然后验证它们是否相同

if(myClass1 == myClass2){
   // objects match
   ...

}

if(myClass1.equals(myClass2)){
   // objects match
   ...

}

但是,这些方法都没有返回真实值。我检查了每个属性,它们匹配。

如何比较这两个对象以验证它们是否相同?

【问题讨论】:

    标签: java object compare


    【解决方案1】:

    你必须正确地覆盖类 Object 中的方法 equals()

    编辑:我认为我的第一反应被误解了,可能是因为我不太准确。所以我决定添加更多的解释。

    为什么你必须重写equals()?好吧,因为这是在开发人员的领域内决定两个对象相等意味着什么。在大多数情况下,引用相等是不够的。

    例如,假设您有一个 HashMap,其键是 Person 类型。每个人都有姓名和地址。现在,您想使用密钥查找详细的 bean。问题是,您通常无法创建具有与地图中的引用相同的引用的实例。您所做的是创建类 Person 的另一个实例。显然,运算符 == 在这里不起作用,您必须使用 equals()。

    但是现在,我们遇到了另一个问题。假设您的收藏非常大,并且您想要执行搜索。天真的实现会使用 equals() 将您的关键对象与地图中的每个实例进行比较。然而,这将是非常广泛的。 hashCode() 来了。正如其他人指出的那样,哈希码是一个不必唯一的数字。重要的要求是,每当 equals() 为两个对象返回 true 时,hashCode() 必须为这两个对象返回相同的值。反推不成立,这是一件好事,因为哈希码将我们的密钥分成不同的桶。我们在单个存储桶中有少量 Person 类的实例。当我们执行搜索时,算法可以立即跳转到正确的存储桶,现在只对每个实例执行 equals。因此,hashCode() 的实现必须在桶中尽可能均匀地分配对象。

    还有一点。某些集合需要在用作键的类中正确实现 hashCode() 方法,这不仅是出于性能原因。示例是:HashSet 和 LinkedHashSet。如果它们不覆盖 hashCode(),则默认 Object hashCode() 方法将允许您可能认为“有意义地”的多个对象 相等”添加到您的“不允许重复”集。

    一些使用hashCode()的集合

    • 哈希集
    • LinkedHashSet
    • 哈希映射

    看看 apache commons 中的这两个类,它们可以让你轻松实现 equals() 和 hashCode()

    【讨论】:

      【解决方案2】:

      您需要在MyClass 中提供自己的equals() 实现。

      @Override
      public boolean equals(Object other) {
          if (!(other instanceof MyClass)) {
              return false;
          }
      
          MyClass that = (MyClass) other;
      
          // Custom equality check here.
          return this.field1.equals(that.field1)
              && this.field2.equals(that.field2);
      }
      

      如果您的对象有可能在哈希表中使用,您还应该覆盖hashCode()reasonable implementation 会将对象字段的哈希码与以下内容结合起来:

      @Override
      public int hashCode() {
          int hashCode = 1;
      
          hashCode = hashCode * 37 + this.field1.hashCode();
          hashCode = hashCode * 37 + this.field2.hashCode();
      
          return hashCode;
      }
      

      有关实现散列函数的更多详细信息,请参阅this question

      【讨论】:

      • @Aubin 通常,质数用于哈希码生成。如果我没记错的话,它会减少生成的哈希值发生冲突的可能性。至于为什么使用 37,我想这只是一个流行的选择,我不知道使用 37 而不是 13 的任何特殊原因。
      • 谢谢你——真的。每个人都让我走上了正确的道路,但我只能接受一个正确的。
      • @John 你的 equals 也可以检查 other == this,虽然这不是必需的,它会在不验证每个字段的情况下返回 true。
      • @ArthurEirich 我现在看到了。不,你是对的,我已经更新了我的答案以匹配链接。
      • @Aubin 我认为 37 来自 Monte Carlo 测试,对 String 的相同测试表明 31 也是可以接受的并且它不太复杂,因此 31 用于 java String hashCode。这在数据结构和算法分析中的图 5.45 中显示。一个清晰的数字可以在faculty.cs.uwlax.edu/~mallen/courses/cs340/lec16.pdf找到
      【解决方案3】:

      您需要覆盖 equalshashCode
      equals 将根据您需要的属性比较对象是否相等,hashCode 是必需的,以便您的对象在 @ 中正确使用987654325@和Maps

      【讨论】:

        【解决方案4】:

        1) == 在这种情况下评估引用相等性
        2) 我不太确定equals,但为什么不简单地重写 compare 方法并将其植入 MyClass 中?

        【讨论】:

          【解决方案5】:

          您需要在MyClass 中实现equals() 方法。

          == 不起作用的原因是检查它们是否引用同一个实例。由于您为每一个都做了new,所以每一个都是不同的实例。

          equals() 不起作用的原因是您还没有自己实现它。我相信它的默认行为与== 相同。

          请注意,如果您要实现 equals(),您还应该实现 hashcode(),因为很多 java.util 集合都期望这样做。

          【讨论】:

          • 很好的解释。简明扼要。
          猜你喜欢
          • 1970-01-01
          • 2013-10-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-20
          • 2020-10-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多