hashCode()与 equals() 之间的关系
一、介绍
简单介绍与一下 hashCode()
与 equals()
1. equals()
equals() 方法用于比较两个对象是否相等,它与 == 相等比较符有着本质的不同。
区别参考:== 和 equals 的区别
2. hashCode()
w3c说明:
hashCode()
方法用于返回字符串的哈希码。
字符串对象的哈希码根据以下公式计算:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
使用 int
算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。空字符串的哈希值为 0。
暂且不谈冲突, 就因为相同的输入能够产生相同的输出这点而言,是及其宝贵的。它使得系统只需要通过简单的运算,在时间复杂度O(1)的情况下就能得出数据的映射关系,根据这种特性,散列表应运而生。
一种主流的散列表实现是:用数组作为哈希函数的输出域,输入值经过哈希函数计算后得到哈希值。然后根据哈希值,在数组种找到对应的存储单元。当发生冲突时,对应的存储单元以链表的形式保存冲突的数据。
二、为什么重写 equals
时必须重写 hashCode
方法?
如果两个对象相等,则 hashcode 一定也是相同的。两个对象相等,对两个对象分别调用 equals 方法都返回 true。但是,两个对象有相同的 hashcode 值,它们也不一定是相等的 。因此,equals 方法被覆盖过,则 hashCode
方法也必须被覆盖。
hashCode()
的默认行为是对堆上的对象产生独特值。如果没有重写hashCode()
,则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
这里贴一个之前看到的
String th = "通话"; String zd = "重地"; System.out.println(th.hashCode());// 1179395 System.out.println(zd.hashCode());// 1179395
三、个人总结
以上内容解释了为什么重写 方法就必须重写 hashCode
方法。这里个人给一个写实体类中为什么要重写equal
方法和 hashCode
方法。都知道像 hashSet
, hashMap
之类的存储是以哈希值来散列的方式存值。 如果实体不重写 hashCode
方法,那么用 这些集合存储时会出现重复的对象,就因为其哈希值不同。这里用 Set 集合测试 ,底层是 hashMap
. 这篇文章末有源码分析带注释 深入探究Java中hashCode()和equals()的关系 。
个人代码:
Student stu1 = new Student("zhangsan", 18);
Student stu2 = new Student("zhangsan", 18);
// 重写 equals()前
// eq false
// 重写后
// eq true
System.out.println(stu1.equals(stu2));
// 重写 hashCode() 前
// Student{name='zhangsan', age=18}
// Student{name='zhangsan', age=18}
// 重写后
// Student{name='zhangsan', age=18}
Set<Student> set = new HashSet<>();
set.add(stu1);
set.add(stu2);
for (Student student : set) {
System.out.println(student);
}
//
Student 类
class Student {
private String name;
private int age;
public Student() {
}
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 student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
//System.identityHashCode() 此方法用于查内存地址
// System.out.println(System.identityHashCode(this));
// System.out.println(System.identityHashCode(o));
// return this == o;
}
// @Override
// public int hashCode() {
// return Objects.hash(name, age);
// }
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}