Java进阶-同时重写 hashCode 和 equals

重点:放在 HashMap 集合 key 部分的元素,以及放在 HashSet 集合的元素,需要同时重写 hashCode 和 equals 方法

  1. 向 Map 集合中存,以及从 Map 集合中取,都是先调用 key 的 hashCode 方法,然后再调用 equals 方法!equals 方法有可能调用,也有可能不调用
  • put(k, v) 举例,什么时候 equals 不会调用?
    • k. hashCode() 方法返回哈希值
    • 哈希值通过哈希算法转换成数组下标
    • 数组下标位置上如果为 null,equals 不需要执行
  • get(k) 举例,什么时候 equals 不会调用?
    • k. hashCode() 方法返回哈希值
    • 哈希值通过哈希算法转换成数组下标
    • 数组下标位置上如果为 null,equals 不需要执行
  1. 注意:如果一个类的 equals 方法重写了,那么 hashCode() 方法必须重写,并且 equals 方法返回如果是 true,hashCode() 方法返回值必须一样

    • equals 方法返回 true,表示两个对象相同,在同一个单向链表上比较,那么对于同一个单向链表上的节点来说,他们的哈希值都是相同的,所以 hashCode() 方法的返回值也应该相同
  2. hashCode() 方法和 equals() 方法不用研究了,直接使用 IDEA 工具生成,但是这两个方法需要同时生成

    • 右键 --> Source --> Generate hashCode() and equals()
  3. 对于哈希表数据结构来说:

    • 如果 o1 和 o2 的 hash 值相同,一定是放到同一个单向链表上
    • 当然如果 o1 和 o2 的 hash 值不同,但由于哈希算法执行结束之后转换的数组下标可能相同,此时会发生“哈希碰撞”
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    import java.util.HashSet;
    import java.util.Set;

    public class HashMapTest02 {

    public static void main(String[] args) {
    Student s1 = new Student("zhangsan");
    Student s2 = new Student("zhangsan");

    // 重写 equals 方法之前是 false
    // System.out.println(s1.equals(s2)); // false

    // 重写 equals 方法之前是 true
    System.out.println(s1.equals(s2)); // true

    System.out.println("s1的hashCode=" + s1.hashCode()); // 2018699554 // 重写后,hashCode变为 -1432604525
    System.out.println("s2的hashCode=" + s2.hashCode()); // 1311053135 // 重写后,hashCode变为 -1432604525

    // s1.equals(s2) 结果已经是 true 了,表示 s1 和 s2 是一样的,那么往 HashSet 集合中放的话,
    // 按说只能放进去 1 个(HashSet 集合特点:无序不可重复)
    Set<Student> students = new HashSet<>();
    students.add(s1);
    students.add(s2);
    System.out.println(students.size()); // 结果是2,显然不符合 HashSet 集合存储特点
    }
    }

    // Student 类
    package test0526;

    public class Student {
    private String name;

    public Student() {

    }

    public Student(String name) {
    this.name = name;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    // hashCode

    // equals(如果学生名字一样,表示同一个学生)
    // public boolean equals(Object obj) {
    // if (obj == null || !(obj instanceof Student))
    // return false;
    // if (obj == this)
    // return true;
    // Student s = (Student) obj;
    // return this.name.equals(s.name);
    // }

    //---- 以下是 IDEA 自动生成
    @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
    }

    @Override
    public boolean equals(Object obj) {
    if (this == obj)
    return true;
    if (obj == null)
    return false;
    if (getClass() != obj.getClass())
    return false;
    Student other = (Student) obj;
    if (name == null) {
    if (other.name != null)
    return false;
    } else if (!name.equals(other.name))
    return false;
    return true;
    }
    }