文章目录
- 1、什么是hashCode
- 2、为什么要有hashCode
- 3、为什么重写 equals 时必须重写 hashCode 方法?
- 4、易错点
1、什么是hashCode
hashCode()是Object定义的方法,它将返回一个整型值,这个方法通常用来将对象的内存地址转换为整数之后返回,它存在的价值是为Hash容器处理数据时提供支持,Hash容器可以根据hashCode定位需要使用的对象,也可以根据hashCode来排除2个不相同的对象,即:hashCode不同,则视为2个对象不同。
2、为什么要有hashCode
哈希码主要在哈希表这类集合映射的时候用到,哈希表存储的是键值对(key-value),它的特点是:能根据“键”快速的映射到对应的“值”。这其中就利⽤到了哈希码。
例如 HashMap 怎么把 key 映射到对应的 value 上呢?用的就是哈希取余法,也就是拿哈希码和存储元素的数组的长度取余,获取 key 对应的 value 所在的下标位置。
3、为什么重写 equals 时必须重写 hashCode 方法?
举例说明:
新建一个User类
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(name, user.name) &&
Objects.equals(age, user.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
上述代码中的equals和hashCode是还没有进行重写的默认原始方法,可以看出,如果没有重写equals方法,那么两个对象进行equals比较时,只有当两个对象的所有属性都相等时,才会认为两个对象相等。
public class Test {
public static void main(String[] args) {
User user =new User();
user.setName("yhz");
user.setAge(18);
User user1 = new User();
user1.setAge(19);
user1.setName("yhz");
System.out.println(user.equals(user1));
}
}
现在只改一下equals:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(name, user.name);
}
现在只要两个User对象的name相同,那么就认为这两个User对象相同。
现在,我new一个HashSet集合,将两个user对象add进去,大家猜猜set里面有几个User
User user =new User();
user.setName("yhz");
user.setAge(18);
User user1 = new User();
user1.setAge(19);
user1.setName("yhz");
System.out.println(user.equals(user1));
Set<User>set= new HashSet();
set.add(user);
set.add(user1);
System.out.println(set);
公布答案:
set里面有两个user对象,欸?上面user.equals(user1)明明返回的是true,我们也知道,Set的特点是不重复,那为什么还会出现两个呢?
原因是: HashSet、HashMap集合在添加元素的时候,用哈希取余法,也就是拿hashCode和存储元素的数组的长度取余,获取 key 对应的 value 所在的下标位置。如果获取到的下标位置上已经存在元素,则认为产生了哈希碰撞(hashCode() 所使用的散列算法也许刚好会让多个对象传回相同的散列值。)再拿新添元素(新的)与当前位置上的元素(旧的)进行equals比较,如果返回true就用新的替换旧的。如果返回false就添加到该位置下面的链表尾或红黑树上。而如果没有发生哈希碰撞,也就间接说明两个对象不相等。然而我们上面只是重写了equals方法(只比较name是否相同),而hashCode返回的还是name和age组合成的数组的hashCode,所以虽然equals返回true,但是两个对象的hashCode不一样,set里存在两个user而不是一个。
HashMap的put过程源码讲解在这里
hashCode() 的默认行为是对堆上的对象产⽣独特值。如果没有重写 hashCode() ,则该 class 的两个对象⽆论如何都不会相等(即使这两个对象指向相同的数据)
现在重写hashCode方法
@Override
public int hashCode() {
return Objects.hash(name);
}
再看一下执行结果:
这回set里只有一个user了。
所以一定记住,重写 equals 方法时必须重写 hashCode 方法。
好了,到这里希望你已经理解重写equals为什么要重写hashcode了😀
4、易错点
- hashCode相等,两个字符串不一定相等。
- hashCode相等,这两个对象不一定相等。
- hashCode不等,这两个对象一定不相等。
- 如果两个对象分别调⽤ equals 方法都返回 true,则这两个对象一定相等。