- 重写子类的euquals方法,为什么一定要重写hashCode方法
public class HashCodeUse {
public static void main(String[] args) {
User user1 =new User("A", "女", 10, 100);
User user2 =new User("A", "女", 10, 100);
System.out.println(user1 == user2); // output:false
System.out.println(user1); //output:com.study.day15.part2.User@17b6ded
System.out.println(user2); //output:com.study.day15.part2.User@17b6ded
System.out.println(user1.equals(user2)); // true
HashMap hashMap = new HashMap();
hashMap.put(user1, "user1的value");
System.out.println(hashMap.get(user2)); // output:user1的值
}
}
class User{
String name;
String gender;
int age;
int score;
public User(String name, String gender, int age, int score) {
this.name = name;
this.gender = gender;
this.age = age;
this.score = score;
}
// 重写User类的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 age == user.age && score == user.score && Objects.equals(name, user.name) && Objects.equals(gender, user.gender);
}
// hashCode方法同时被重写
@Override
public int hashCode() {
return Objects.hash(name, gender, age, score);
}
}
// 在HashMap的使用过程中会用到euqal方法,如果不改写hashcode值就会出现hash(user1)
// 不等于hash(user2),但是equals却相等的情况,会发生冲突;
-
逐步理解hashMap的相关概念:
-
基于hash算法的数据结构:hashMap(哈希映射),hashSet(hash集合),hashtable(hash表)
-
首先理解哈希表(逻辑结构)
哈希表以哈希函数h作为对应关系,目的是为了在查询目标记录时不需要进行遍历比较,而是一次直接获得想要的结果。因此将目标记录与其关键字之间建立一个哈希函数关系h,使每个关键字和结构中一个唯一的存储位置相对应。从而给定关键字key和对应关系h,通过h(key)找到目标记录value;
-
hash表是一种逻辑结构,而hashMap和hashTable是Java中的数据结构,他们通过实现Hash表实现了相应的操作;
-
hashMap
HashMap中的put(key,value)和get(key)方法,HashMap是使用hash算法,然后基于数组+链表+红黑树来实现的,HashMap内部数组的初始长度为16,并且还能自动扩容。探究一下put(key,value)和get(key)这两个常用的方法的实现过程和原理.
-
put(key,value)的原理
调用put方法的时候,方法内部会调用hash(key)方法,计算出key的hash值h,然后通过HashMap的主干部分(数组tab)的长度length来进行位与运算(length-1)&h得出一个index=(length-1)&h值,然后直接根据index的值,将Node对象放入对应的tab[index]=Node即可
-
get(key)的原理
一般情况下,首先根据key值调用方法hash(key),通过与数组长度位与运算来计算出index值,然后直接返回tab[index].value即可.
但是当计算出的index处的Node对象是链表结构或红黑树时,这个时候会使用node.next来依次遍历比较链表上每个Node对象节点的key值是否和传入的key相等,直到匹配上为止。
-
-
hashMap的概念图
- HashMap设计中选择了equals方法,所以对于不同的实例化对象,如果重写了父类equals方法,而不该写相应的hashcode()方法的话,可能相同属性的对象却拥有不同的hashcode()值,观察一下HashMap的get(key)操作,使用node.next来依次遍历比较链表上每个Node对象节点的key值是否和传入的key相等,也就是使用了key的equals()方法,在这种情况下,如果自己的类覆盖了equals()方法而没有管hashCode()方法,那么,在put(key)方法中,依赖hashCode计算出index这一步,就会将原本equals()的对象放在不同index中,这样接下来的覆盖操作就不会起作用了。造成的结果是,相等的对象被放入了不同index位置,而不是覆盖。