程序员老鬼

Java面试题:hashcode相等两个类一定相等吗?equals呢?相反呢?

今天我们来聊一聊一个常见的Java面试题:hashCode相等,两个对象一定相等吗?equals呢?相反呢?

这个问题经常出现在Java面试中,很多人回答时都会有点困惑。其实它考察的不仅仅是你对hashCode()和equals()方法的理解,更是你对Java对象比较机制的深度认知。

我自己第一次遇到这个问题时,感觉自己答得还算可以,但是回去深挖了下发现,嘿,原来我并没有完全理解这其中的细节。所以今天咱们就一起来理清这个问题,把它讲透。

先聊聊 hashCode() 和 equals() 这两个方法

首先,我们得理解一下这两个方法的作用。说白了,hashCode() 和 equals() 都是用来比较对象的。但是它们在底层的工作机制和比较方式上有着本质的不同。

  1. hashCode():

  • hashCode() 是一个方法,定义在 Object 类中。它的作用是返回对象的哈希值,这是一个整数,通常用于存放对象在散列结构中(比如 HashMap, HashSet)的位置。
  • 比如说,hashCode() 就像是一个对象的“身份证号码”,在哈希表中会用来快速定位对象所在的桶(bucket)。但它并不保证两个对象的哈希值必须唯一,只是说两个对象的哈希值相等时,它们有可能是相同的对象,但不能证明它们必定是相同的。
  • equals():

    • equals() 也是定义在 Object 类中的方法,通常用来比较两个对象是否相等。与 hashCode() 不同,equals() 是用来比较对象的内容,而不是它们在内存中的位置。
    • 如果我们在自定义类中覆盖了 equals(),那就意味着我们为该类定义了什么样的“相等标准”。比如,对于一个 Person 类来说,equals() 可能会比较 name 和 age 是否一致,而不仅仅是判断它们是否是同一个对象的引用。

    回到问题:“hashCode 相等,两个对象一定相等吗?equals 呢?相反呢?”

    1. hashCode() 相等,两个对象一定相等吗?

    这里的答案是不一定。我们来做个简单的示例:

    class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public int hashCode() {
            return name.hashCode() + age;  // 假设简单计算hashCode
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            Person person = (Person) obj;
            return age == person.age && name.equals(person.name);
        }
    }

    public class Test {
        public static void main(String[] args) {
            Person p1 = new Person("John", 25);
            Person p2 = new Person("John", 25);
            System.out.println(p1.hashCode() == p2.hashCode());  // true
            System.out.println(p1.equals(p2));  // true
        }
    }

    在这个例子中,我们定义了一个 Person 类,重写了 hashCode() 和 equals()。我们可以看到,虽然 p1 和 p2 的内容相同(名字和年龄一样),它们的 hashCode() 相等,但它们依然是两个不同的对象。如果你直接比较它们的引用地址(通过 ==),结果会是 false,因为它们是不同的实例。

    但是如果你调用 equals(),因为我们在 equals() 方法中检查了 name 和 age,那么它们被认为是相等的。

    所以说,hashCode() 相等并不能保证两个对象是相等的,除非你也重写了 equals(),并且在 equals() 中按照某种规则判断它们是否相等。

    2. equals() 相等,两个对象一定相等吗?

    如果两个对象通过 equals() 比较是相等的,那它们的内容在逻辑上是一样的。不过这并不代表它们的哈希值一定相同。比如你重写了 equals(),但是没有重写 hashCode()。在这种情况下,两个内容相同的对象,equals() 会返回 true,但是它们的 hashCode() 可能不相同。这样,哈希表就不能确保它们在 HashMap 或 HashSet 中被正确定位。

    举个例子:

    class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            Person person = (Person) obj;
            return age == person.age && name.equals(person.name);
        }
    }

    public class Test {
        public static void main(String[] args) {
            Person p1 = new Person("John", 25);
            Person p2 = new Person("John", 25);
            System.out.println(p1.equals(p2));  // true
            System.out.println(p1.hashCode() == p2.hashCode());  // false (如果没有重写hashCode)
        }
    }

    这里我们没有重写 hashCode(),所以 p1 和 p2 虽然在 equals() 上返回 true,但它们的 hashCode() 可能不相等,这会导致它们在哈希表中的行为不符合预期。

    3. 相反的情况:hashCode 不等,equals 一定不等吗?

    如果两个对象的 hashCode() 不相等,那这两个对象一定不相等。为什么呢?因为哈希值本身是计算对象内容的一部分。两个对象如果有不同的 hashCode(),那它们肯定不相等。这个规则是由 hashCode() 方法的设计所决定的。

    实际上,Java 的规范就明确要求:如果两个对象的 hashCode() 不相等,它们通过 equals() 比较时一定不相等。所以如果你在实现 hashCode() 方法时没有遵循这个规则,那就可能导致一些意料之外的结果,甚至会影响到 HashMap 和 HashSet 的行为。

    总结

    总的来说,hashCode() 和 equals() 的关系其实很微妙。它们的相互配合决定了对象在哈希表中的行为。如果你想要保证对象在 HashMap 或 HashSet 中正确的比较和存储,记得遵循 Java 的规范:如果重写了 equals(),一定要同时重写 hashCode(),并且要确保 hashCode() 的一致性。

    至于面试时的答案,记住:hashCode 相等并不意味着 equals 相等,而 equals 相等也不一定 hashCode 相等。这两个方法的实现需要符合 Java 的约定,才能保证它们在各种数据结构中的正确性。

    那么,我猜你现在一定能在面试时轻松应对这个问题了吧!😎

    -END-

    ok,今天先说到这,老规矩,给大家分享一份不错的副业资料,感兴趣的同学找我领取。

    Image

    以上,就是今天的分享了,看完文章记得右下角给何老师点赞,也欢迎在评论区写下你的留言。