
为什么要重写hashCode()和equals()方法?
Coding的哔哔叨叨
结论:
重写equals()是为了实现自己的区分逻辑。
重写hashCode()是为了提高hash tables的使用效率,以及和equals()保持一致。
🙋过程分析:
一段代码先奉上:
class Student{private Integer age;private String name;public Student(Integer age,String name){this.age=age;this.name=name;}}public static void main(String[] args) {Student s1 = new Student(10, "Bob");Student s2 = new Student(10, "Bob");System.out.println(s1.equals(s2));System.out.println(s1.hashCode());System.out.println(s2.hashCode());}
false1537358694804581391
下面开始我们的分析,为什么要重写hashCode()和equals()方法?
要回答这个问题,我们需要清楚java原生的equals()方法是怎么进行比较的。
在没有重写hashCode()和equals()方法的类中,对象进行equals比较,实际是调用了Object类中的equals()方法。
Object类中的equals()方法进行对象比较实际是对象内存地址的比较,上面s1和s2对象明显是new了两个对象,所以内存地址一定是不同的,所以结果是false。
//Object类中的equals()方法。public boolean equals(Object obj) {//比较的是两个对象的内存地址return (this == obj);}
Object类中的hashCode()方法是一个本地方法,hashCode值是根据对象内存地址经哈希算法得来的。
public native int hashCode();
java中规定:
两个对象的equals()相同,hashCode一定相同。 两个对象的equals()不同,hashCode不一定不同。 hashCode相同,但equals不一定相同。 hashCode不同,equals一定不同。
在实际的开发应用中,我们经常要把对象存到集合当中,如Map、Set,我们都知道Map中key是不能重复的,java中判断key是否重复使用的就是equals()方法和hashCode()方法。
//摘抄至源码中if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))
而我们在实际中,对于上面s1和s2更愿意理解为是同一个对象,也是说假设我们将上面两个对象放到HashSet中,更希望得到的体现是两个对象是一样的,在HashSet中只保留一个,所以我们需要重写equals()和hashCode()方法来重新定义对象是否相等的条件,保证集合中存储的对象是不同。
/*** 重写hashCode和equal方法*/class Student{private Integer age;private String name;public Student(Integer age,String name){this.age=age;this.name=name;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (!(o instanceof Student)) return false;Student s = (Student) o;if (age != s.age) return false;return name.equals(s.name);}@Overridepublic int hashCode(){int result = name.hashCode();result = 31 * result + age;return result;}}public static void main(String[] args) {Student s1 = new Student(10, "Bob");Student s2 = new Student(10, "Bob");System.out.println(s1.equals(s2));System.out.println(s1.hashCode());System.out.println(s2.hashCode());}// true// 2075925// 2075925
hashCode()和equals()方法重写为啥是成对的出现?
Coding的哔哔叨叨
只重写equals()方法。
只重写hashCode()方法。
重写hashCode()为什么选用31作为乘数。
Coding的哔哔叨叨
结论:
更少的乘积结果冲突。
31可以被jvm优化。
更少的乘积结果冲突。
31是质子数中一个“不大不小”的存在,如果你使用的是一个如2的较小质数,那么得出的乘积会在一个很小的范围,很容易造成哈希值的冲突。而如果选择一个100以上的质数,得出的哈希值会超出int的最大范围,这两种都不合适。而如果对超过 50,000 个英文单词(由两个不同版本的 Unix 字典合并而成)进行 hash code 运算,并使用常数 31, 33, 37, 39 和 41 作为乘子,每个常数算出的哈希值冲突数都小于7个(国外大神做的测试),那么这几个数就被作为生成hashCode值的备选乘数了。
31可以被jvm优化
JVM里最有效的计算方式就是进行位运算了:
左移 << : 左边的最高位丢弃,右边补全0(把 << 左边的数据*2的移动次幂)。 右移 >> : 把>>左边的数据/2的移动次幂。 无符号右移 >>> : 无论最高位是0还是1,左边补齐0。 所以:31 * num = (32-1) * num= 32*num-num=(2<<5)*num-num,JVM就可以高效的进行计算啦。
不积跬步,无以至千里。
文章有帮助的话,点个转发、在看呗
。
谢谢支持哟 (*^__^*)
END
👇





。