为什么要重写 hashcode 和 equals 方法?
-
例如有两个自定义对象 MyKey, MyKey 有属性 id
-
class MyKey{ private Integer id; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public MyKey(Integer id) { this.setId(id); } }
-
新建两个 id 为 10 的 MyKey 对象后放入 HashMap
-
MyKey k1 = new MyKey(10); MyKey k2 = new MyKey(10); HashMap<MyKey,String> map = new HashMap<>(); map.put(k1,"test");
-
当 k1 存入 map 中时,调用 MyKey 类的 hashCode 方法获取 hashCode 存入在 map 中 hashCode 指引的内存位置,我们不重写 hashCode 就默认调用 Object 的 hashCode 方法也就是获取了 k1 的内存地址例如 0x10
-
当取 HashMap 时:
map.get(k2);
按道理应该取出 “test” -
但是因为没有重写 hashCode 依旧默认调用 Object 类的 hashCode 方法,获取对象内存地址比如 k2 内存地址为 0x20,你用 0x20 这个hashCode 怎么取 0x10 这个 hashCode 对应的东西呢。
-
所以重写 hashCode
-
@Override public int hashCode(){ return id.hashCOde(); }
-
这样就能返回相同的 hashCode
-
但是重写 hashCode 后还是取不到
-
因为 HashMap 是用链地址法来处理冲突,同样的 hashCode 对应的地址可能存在多个用链表形式存储的对象,也就是说这个地址上的兄弟的 hashCode 都是一样的,当你 hashCode 相同时就调用 equals 看你是否是同一个对象。
-
那么 Object 的 equals 比较的还是对象在内存中存储的地址,所以又变成了 0x10 和 0x20 的比较,所以还得重写 equals 方法
-
@Override public boolean equals(Object obj){ if(this == obj){ return true; } if(obj instanceof Mykey){ return this.getId().equals(((MyKey)obj).getId()); } return false; }
-
这样 k1 和 k2 的 hashCode 相同,且 equals