为什么重写equals()同时也要重写hashcode()?

本文最后更新于:3 年前

hd.jpg

Hashcode和equals的知识点。

Hashcode

Hashcode的作用

获取哈希码(为int数据类型)。

哈希码(散列码)的作用

确定该对象在哈希表中的位置。

哈希表的作用

在栈中(利用哈希码)快速找到对象的位置。

key-value 对储存。

哈希冲突

由于哈希算法被计算的数据是无限的,而计算后的结果范围有限,因此总会存在不同的数据经过计算后得到的值相同,这就是哈希冲突。(两个不同的数据计算后的结果一样)

hashset的录入过程

image-20210811233756996

简易流程图

image-20210811234941094

使用Hashcode的意义

在比较equals之前,先比较hashcode可以大大减少使用equals的次数提高执行的性能

equals

所有类继承object类中的equals()方法,**默认使用的是==**。

==和equals

==为对比栈中的数据。

  • 基本类型数据:比对变量值
  • 引用类型数据: 比对对象的地址
1
2
3
4
5
6
7
String s1 = "abc";
String s2 = "abc";
System.out.println("s1的hashcode:" + s1.hashCode());
System.out.println("s2的hashcode:" + s2.hashCode());
System.out.print("s1 == s2:" );
System.out.println( s1 == s2);
System.out.println("s1.equals(s2):" + s1.equals(s2));

结果:

1
2
3
4
s1的hashcode:96354
s2的hashcode:96354
s1 == s2:true
s1.equals(s2):true

String重写equals

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

对每个char进行对比。

为什么重写equals()必须重写hashcode()

hashcode的使用原则

  • 对象相等,hashcode必须相等
  • hashcode相等,对象不一定相等
  • 两对象相等,则equals相等
  • hashcode()的默认行为是对堆上的对象产生独特值。如果没有重写hashcode,则同一class的两个对象无论如何也不会相等。

代码验证

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
package com.ajie.controller;

import java.util.HashMap;

/**
* @description: some desc
* @author: septzhang
* @email: 1339126726@qq.com
* @Date: 2021/8/11 23:31
*/
public class Test {
public static void main(String[] args) {
Student s1 = new Student("Tom", 12);
Student s2 = new Student("Tom", 12);
System.out.println("s1 equals s2 ?"+s1.equals(s2));
System.out.println("s1 hashCode:"+s1.hashCode());
System.out.println("s2 hashCode:"+s2.hashCode());
HashMap<Student, Integer> hashMap = new HashMap<Student, Integer>();
hashMap.put(s1, 1);
System.out.println(hashMap.get(s2));
}
}
class Student {
private String name;
private int age;

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

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

}

运行结果

1
2
3
4
s1 equals s2 ?true
s1 hashCode:366712642
s2 hashCode:1829164700
null

我们Student类重写了equals方法,hashCode方法没有重写.

s1和s2是同一class生成的两个属性相同的对象,equals方法为true,认为是同一个人。但是s1和s2的hashCode返回不同。

参考

Java重写equals方法时为什么要重写hashCode方法_掘客DIGGKR-CSDN博客

限时分享!阿里P8熬了2个月肝出500道Java面试必考题(最全面系统的Java核心知识点)_哔哩哔哩_bilibili


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!