重写equal方法后需要重写hashcode方法

落日映苍穹つ 2024-03-30 16:07 223阅读 0赞

hashCode1 和 equals2 协同判断两个对象是否相同

  • equals 方法和 hashCode 方法是 Object 类中的两个基础方法当我们对比两个对象是否相等时,我们就可以先使用 hashCode 进行比较,如果比较的结果是 true,那么就可以使用 equals 再次确认两个对象是否相等,如果比较的结果是 true,那么这两个对象就是相等的,否则其他情况就认为两个对象不相等。这样就大大的提升了对象比较的效率,这也是为什么 Java 设计使用 hashCode 和 equals 协同的方式,来确认两个对象是否相等的原因。
  • 那为什么不直接使用 hashCode 就确定两个对象是否相等呢?
    这是因为 如果两个对象相等,则hashcode一定也是相同的;两个对象有相同的hashcode值,它们并不一定是相等的。

equals方法说明

  • Object 类中的 equals 方法用于检测一个对象是否等于另外一个对象。在 Object 类中,这个方法将判断两个对象是否具有相同的引用。如果两个对象具有相同的引用,它们一定是相等的。

    public boolean equals(Object obj) {

    return (this == obj);
    }

    /*
    */
    class User {

    1. private String name;
    2. private Integer age;
    3. public User(String name, Integer age) {
    4. this.name = name;
    5. this.age = age;
    6. }
    7. public String getName() {
    8. return name;
    9. }
    10. public void setName(String name) {
    11. this.name = name;
    12. }
    13. public Integer getAge() {
    14. return age;
    15. }
    16. public void setAge(Integer age) {
    17. this.age = age;
    18. }

    }

    public class EqualsMethodTest {

    1. public static void main(String[] args) {
    2. User u1 = new User("张起灵", 18);
    3. User u2 = new User("张起灵", 18);
    4. System.out.println(u1.equals(u2));
    5. }

    }
    输出为 false

  • 通常情况下,我们要判断两个对象是否相等,一定要重写 equals 方法.

  • 8种数据类型的包装类、String这些类都重写了equals方法的。

hashCode 方法说明

  • hashCode 翻译为中文是散列码,它是由对象推导出的一个整型值,并且这个值为任意整数,包括正数或负数。需要注意的是:散列码是没有规律的。如果 x 和 y 是两个不同的对象,x.hashCode() 与 y.hashCode() 基本上不会相同(有可能相同);但如果 a 和 b 相等,则 a.hashCode() 一定等于 b.hashCode()。
    源码

    public native int hashCode();

  • 在不重写hashcode方法时的源码

    /*
    */
    class People {

    1. private String name;
    2. private Integer age;
    3. public People(String name, Integer age) {
    4. this.name = name;
    5. this.age = age;
    6. }
    7. public String getName() {
    8. return name;
    9. }
    10. public void setName(String name) {
    11. this.name = name;
    12. }
    13. public Integer getAge() {
    14. return age;
    15. }
    16. public void setAge(Integer age) {
    17. this.age = age;
    18. }

    }

    public class HashCodeMethodTest {

    1. public static void main(String[] args) {
    2. People p1 = new People("张起灵", 18);
    3. People p2 = new People("张起灵", 18);
    4. System.out.println(p1.hashCode());
    5. System.out.println(p2.hashCode());
    6. }

    }

  1. 输出
  2. 19291231313
  3. 20232252525

-重写hashCode之后,两个对象相同,它们的hashCode值相同。

为什么需要equal和hashcode都需要同时重写?

这是要保证宏观条件上的两个属性值相同的两个对象的进行比较时为true

  • 1、Set 集合是用来保存不同对象的,相同的对象就会被 Set 合并,最终留下一份独一无二的数据。

    import java.util.HashSet;
    import java.util.Set;

    /*
    */
    public class EqualsHashCodeTest {

    public static void main(String[] args) {

    1. Set<String> set = new HashSet<>();
    2. set.add("Java");
    3. set.add("Java");
    4. set.add("SpringBoot");
    5. set.add("SpringBoot");
    6. set.add("SpringBoot");
    7. set.add("Redis");
    8. System.out.println("set集合的长度为:" + set.size());
    9. set.forEach(System.out::println);

    }
    }

  1. 输出结果为
  2. set集合的长度为:3
  3. java
  4. SpringBoot
  5. Redis
  • 编写一个类,重写equals(),不重写hashcode()

    import java.util.HashSet;
    import java.util.Objects;
    import java.util.Set;

    /*
    */
    class Student {

    1. private String name;
    2. private Integer age;
    3. public Student(String name, Integer age) {
    4. this.name = name;
    5. this.age = age;
    6. }
    7. public String getName() {
    8. return name;
    9. }
    10. public void setName(String name) {
    11. this.name = name;
    12. }
    13. public Integer getAge() {
    14. return age;
    15. }
    16. public void setAge(Integer age) {
    17. this.age = age;
    18. }
    19. @Override
    20. public boolean equals(Object o) {
    21. if (this == o) return true;
    22. if (o == null || getClass() != o.getClass()) return false;
    23. Student student = (Student) o;
    24. return Objects.equals(name, student.name) && Objects.equals(age, student.age);
    25. }

    // @Override
    // public int hashCode() {

    // return Objects.hash(name, age);
    // }

    1. @Override
    2. public String toString() {
    3. return "Student{" +
    4. "name='" + name + '\'' +
    5. ", age=" + age +
    6. '}';
    7. }

    }

    public class EqualsHashCodeTest {

    1. public static void main(String[] args) {
    2. Set<Student> set = new HashSet<>();
    3. set.add(new Student("张起灵", 18));
    4. set.add(new Student("张起灵", 18));
    5. System.out.println("set集合的长度为:" + set.size());
    6. set.forEach(System.out::println);
    7. }

    }

  1. 输出结果
  2. set集合的长度为: 2
  3. Student(name = 张起灵, age = 18)
  4. Student(name = 张起灵, age = 18)
  5. - 即使两个对象是相等的,Set 集合竟然没有将二者进行去重与合并。这就是重写了 equals 方法,但没有重写 hashCode 方法的问题所在。
  6. 解决上述问题,自然就是在重写equals的同时一定要重写hashCode!!!
  • 重写hashcode方法

    import java.util.HashSet;
    import java.util.Objects;
    import java.util.Set;

    /*
    */
    class Student {

    1. private String name;
    2. private Integer age;
    3. public Student(String name, Integer age) {
    4. this.name = name;
    5. this.age = age;
    6. }
    7. public String getName() {
    8. return name;
    9. }
    10. public void setName(String name) {
    11. this.name = name;
    12. }
    13. public Integer getAge() {
    14. return age;
    15. }
    16. public void setAge(Integer age) {
    17. this.age = age;
    18. }
    19. @Override
    20. public boolean equals(Object o) {
    21. if (this == o) return true;
    22. if (o == null || getClass() != o.getClass()) return false;
    23. Student student = (Student) o;
    24. return Objects.equals(name, student.name) && Objects.equals(age, student.age);
    25. }
    26. @Override
    27. public int hashCode() {
    28. return Objects.hash(name, age);
    29. }
    30. @Override
    31. public String toString() {
    32. return "Student{" +
    33. "name='" + name + '\'' +
    34. ", age=" + age +
    35. '}';
    36. }

    }

    public class EqualsHashCodeTest {

    1. public static void main(String[] args) {
    2. Set<Student> set = new HashSet<>();
    3. set.add(new Student("张起灵", 18));
    4. set.add(new Student("张起灵", 18));
    5. System.out.println("set集合的长度为:" + set.size());
    6. set.forEach(System.out::println);
    7. }

    }

  1. 输出结果:
  2. set集合的长度为:1
  3. Student(name =张起灵,age =18)
  • 但是,如果在重写 equals 方法时,也重写了 hashCode 方法,那么在执行判断时会去执行重写的 hashCode 方法,此时对比的是两个对象的所有属性的 hashCode 是否相同,于是调用 hashCode 返回的结果就是 true,再去调用 equals 方法,发现两个对象确实是相等的,于是就返回 true 了,因此 Set 集合就不会存储两个一模一样的数据了,于是整个程序的执行就正常了。

1、对于基本类型和引用类型 == 的作用效果是不同的,如下所示:

  • 基本类型:比较的是值是否相同;
  • 引用类型:比较的是引用是否相同;

2、重写引用类型的equals方法是为了将引用比较改成值的比较

3、两个对象的 hashCode() 相同,则 equals() 也一定为 true,这是不对的。

  1. String str1 = "通话";
  2. String str2 = "重地";
  3. System. out. println(String. format("str1:%d | str2:%d", str1. hashCode(),str2. hashCode()));
  4. System. out. println(str1. equals(str2));

执行结果:

  1. str11179395 | str21179395
  2. false

发表评论

表情:
评论列表 (有 0 条评论,223人围观)

还没有评论,来说两句吧...

相关阅读