【问题标题】:Why this two simple objects are not equal?为什么这两个简单的对象不相等?
【发布时间】:2025-12-11 09:35:01
【问题描述】:

我有一个学校课程:

public class School {

    private String name;
    private int id;
    private boolean isOpen;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public boolean isOpen() {
        return isOpen;
    }
    public void setOpen(boolean isOpen) {
        this.isOpen = isOpen;
    }
}

然后我创建了两个School实例,比较两个实例的相等性:

public static void main(String[] args) {
        //school1
        School school1 = new School();
        school1.setId(1);
        school1.setName("schoolOne");

        //school2
        School school2 = new School();
        school2.setId(1);
        school2.setName("schoolOne");

            //result is false , why?
        System.out.println("school1 == school2 ? " + school1.equals(school2));

    }

即使我将相同的idname 设置为school1school2 实例,但school1.equals(school2) 返回false,为什么?

【问题讨论】:

  • 您没有覆盖类中的 equals 方法。所以你得到默认行为,即public boolean equals(Object obj) {return (this == obj);}。由于您正在创建两个全新的对象,因此它返回 false。如果你已经完成School school2 = school1;,它会输出true。
  • 如果您使用的是 Eclipse,您可以通过右键单击类 > Source > Generate Hashcode() 和 equals() 来生成 equals() 方法
  • 看看这个问题的答案它可能对你有帮助*.com/questions/16069106/…

标签: java


【解决方案1】:

你必须重写 equals(Object) 方法:

把它放在你的学校班级里:

@Override
public boolean equals(Object other) {
    if (other == this) return true;
    if (other == null || !(other instanceof School)) return false;
    School school = (School) other;
    if (school.id != this.id) return false;
    if (!(school.name.equals(this.name))) return false;
    if (school.isOpen != this.isOpen) return false;
    if (!(school.hashCode().equals(this.hashCode()))) return false;
    return true;
}

如果您打算这样做,最好也重写hashCode() 方法。

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (int) id;
    result = prime * result + (name != null ? name.hashCode() : 0);
    result = prime * result + (isOpen ? 0 : 1);
    return result;
}

其他信息

我相信这是覆盖hashCode()的最好解释。

此答案由 dmeister 为以下帖子发布:SO: Hash Code implementation

我一直引用这个,看起来这个功能在 Eclipse 中为给定类生成 hashCode() 方法时使用。

在几乎所有情况下都提出了合理的良好实施方案 Josh Bloch 的《Effective Java》第 8 条。最好的就是看它 因为作者在那里解释了为什么这种方法很好。

一个简短的版本:

  1. 创建一个 int 结果并分配一个非零值。

  2. 对于在 equals 方法中测试的每个字段,通过以下方式计算哈希码 c:

    • 如果字段 f 是布尔值:计算 (f ? 0 : 1);
    • 如果字段 f 是 byte、char、short 或 int:计算 (int)f;
    • 如果字段f是long:计算(int)(f ^ (f >>> 32))
    • 如果字段 f 是浮点数:计算 Float.floatToIntBits(f);
    • 如果字段 f 是 double:计算 Double.doubleToLongBits(f) 并像处理每个 long 值一样处理返回值;
    • 如果字段 f 是一个对象:使用hashCode() 方法的结果或0 如果f == null;
    • 如果字段 f 是一个数组:将每个字段视为单独的元素,并且 以递归方式计算哈希值并组合这些值 如下所述。

  3. 将哈希值 c 与结果结合:

    result = 37 * result + c

  4. 返回结果

    对于大多数使用情况,这应该会导致哈希值的正确分布。

【讨论】:

  • hashCode 方法呢?
  • 答案中仍应提及,无需提供实现,但提出问题的人必须意识到这一点。
【解决方案2】:

想象一下双胞胎(在现实生活中),即使他们长相相同、年龄相同、名字相同,他们是否平等?不,它们不是,它们是两个不同的“实例”。

在 Java 中也是如此。两个不同的实例不能(隐式)相等,因为它们各自独立存在于各自的内存部分中。

但是,如果您想像这样比较它们,您可以覆盖 equals() 方法,也可以创建自己的新方法进行比较。

【讨论】:

    【解决方案3】:

    即使我为 school1 和 school2 实例设置了相同的 id 和名称,但 school1.equals(school2) 返回 false,为什么?

    您需要在您的 School 课程中覆盖 equals() 方法。否则 Object 类的默认方法实现。

    查看默认实现

    public boolean More ...equals(Object obj) {
            return (this == obj);
        }
    

    在您的情况下,它是false,因为您正在创建两个对象。有道理吗??

    对于解决方案 Prefer to read

    【讨论】:

    • @downvoter 你能解释一下原因吗?
    • 您急于先回答,您的“回答”中有几个拼写错误。你现在要做的就是添加一些小部分,直到它成为一个不错的答案。即使是现在,仍然没有解决方案。
    • @JeroenVannevel 覆盖 equals 方法不是解决方案?
    • 这是一般的解决方案,但“给每个人一块面包”也不是结束世界饥饿的解决方案。如果您要给出的答案基本上是“这是解决方法,现在用谷歌搜索”,那么这不是答案。要么将其标记为他在谷歌搜索后最终会出现的问题的副本,要么提供一个解释为什么必须这样做以及什么必须完成的答案具体来说。
    • @JeroenVannevel 好吧,您还没有阅读实际问题。 OP在问为什么它是错误的。我希望我能解释一下。
    【解决方案4】:

    您必须有意义地覆盖equals() 方法。从Object类继承的默认equals()方法检查两个引用是否引用内存中的同一个对象。

    Object类的equals方法实现了最区分 对象上可能的等价关系;也就是说,对于任何非空 参考值 x 和 y,此方法返回 true 当且仅当 x 和 y 引用同一个对象(x == y 的值为 true)。

    【讨论】:

      【解决方案5】:

      您创建了 2 个新对象。现在您正在比较 2 个对象引用...您不是在比较字段成员值。所以比较是错误的。

      对于原始数据类型,您不会有这个问题。

      【讨论】:

        【解决方案6】:

        如果你不重写公共布尔equals(Object)方法,将调用Object.class中的版本:

        public boolean equals(Object obj) {
            return (this == obj);
        }
        

        只需比较引用(如果它们是完全相同的对象)!

        因此,您必须在 School.class 中实现自己的 equals(Object)。比较这些字段:

        private String name;  // use String.equals(String)
        private int id;  // use ==
        private boolean isOpen; // use ==
        

        【讨论】:

          【解决方案7】:

          默认情况下, .equals() 执行 "==" 即,comapring 引用。你必须重写equals()。

          【讨论】:

            【解决方案8】:

            简单的答案是,隐式超类Object的equals被用于比较。

            来自文档:

            Object 类的 equals 方法实现了对象上最有区别的可能等价关系;也就是说,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象(x == y 的值为 true)时,此方法才返回 true。 Equals method

            您必须在 Student 类中覆盖 equals 和 hashcode 方法。

            【讨论】:

              【解决方案9】:

              如果不覆盖equals(),那么Java.lang.Object中默认的equals()会被调用:

              public boolean equals(Object obj) {
                      return (this == obj);
                  }
              

              如您所见,它比较两个对象的引用,因此在您的情况下它返回 false。

              如果要比较两个对象的内容,可以:

              @Override
              public boolean equals(Object obj) {
                  // A simple impl. Pls add some checking for null/class type/.. yourself
                  return this.name.equals(obj.getName()) && this.id == obj.getId() && this.isOpen == isOpen();
              }
              

              【讨论】: