一、问题引入
平时在开发中,相信你多多少少都使用过 HashMap ,而当你用自定义对象作为 key 时,很多人会告诉你:你必须要同时实现自定义对象的 hashCode、equals 方法,否者可能会出问题,于是你就实现了...
可是为什么呢?比如这里有自定义对象 Person ,构造如下:
1
2
3
4
5
|
public class Person {
private String name;
private int age;
private float height;
}
|
欲将 Person 作为 HashMap的key ,放入哈希表中存储信息。我们来探讨一下,为什么要同时实现 hashCode、equals 方法吧~
1
2
3
4
5
|
Person p1 = new Person( "ciusyan" , 21 , 1 .8f);
Person p2 = new Person( "ciusyan" , 21 , 1 .8f);
Map<Person, String> map = new HashMap<>();
map.put(p1, "Ciusyan" );
map.put(p2, "Zhiyan" );
|
首先要明确:
hashCode 方法用于 计算出对象的哈希值 equlas 方法用于 比较两个对象是否相等
二、hashCode、equals方法都未实现
倘若你了解哈希表的基本构造,可以画出一个草图:
我们并没有实现 hashCode、equals 方法,为什么还能放入哈希表中呢?
因为 JDK 会有默认实现在默认的实现中:
利用 hashCode 方法计算出的哈希值是不同的 利用 equals 方法比较, p1和p2 不是一个对象 所以放入哈希表中的大致结构如上图所示: 可能会被放入两个桶 (不同哈希值计算出的索引不一样) 也可能会被放入一个桶 (不同哈希值也可能会计算出相同的索引) ,又因为是不同对象,所以会被串起来
三、只实现hashCode方法
如果我们实现了 hashCode 方法,会有什么不同呢?
1
2
3
4
5
6
7
|
@Override
public int hashCode() {
int hash = Integer.hashCode(age);
hash = hash * 31 + Float.hashCode(height);
hash = hash * 31 + (name == null ? 0 : name.hashCode());
return hash;
}
|
如上实现,既满足了尽量用的所有信息,也使计算的值尽量唯一了
如果是现在,我们再来画一幅草图:
现在只实现了 hashCode 方法:
利用 hashCode 方法计算出的哈希值是相同的 equals 方法是默认实现, p1和p2 不是一个对象 所以放入哈希表中的大致结构如上图所示: 只会被放入一个桶(相同的哈希值计算出的索引相同),又因为是不同对象,所以会被串起来
四、只实现equals方法
如果我们实现了 equals 方法,会有什么不同呢?
1
2
3
4
5
6
7
|
@Override
public boolean equals(Object o) {
if ( this == o) return true ;
if (o == null || o.getClass() != getClass()) return false ;
Person p = (Person) o;
return p.age == age && p.height == height && (Objects.equals(name, p.name));
}
|
如上实现,如果两个对象的 age、name、height 都相等,那么可以认为是同一个对象
如果是现在:
现在只实现了 equals 方法:
hashCode 方法是默认实现,计算出的哈希值是不同的 利用 equals 方法比较, p1和p2 是同一个对象 所以放入哈希表中的大致结构如上图所示: 可能会被放入两个桶 (计算出的索引不一样) 也可能会被放入一个桶 (不同哈希值也可能会计算出相同的索引) ,又因为是同一对象,所以p2的键和值会覆盖掉p1的
五、hashCode、equals方法都实现
倘若我们用上面的实现方式,将 hashCode和equals 方法都实现了
来看看最终的结构:
现在 hashCode、equals 方法都实现了:
利用 hashCode 方法计算出的哈希值是相同的 利用 equals 方法比较, p1和p2 是同一个对象所以放入哈希表中的大致结构如上图所示:
只会被放入一个桶中 (相同的哈希值计算出的索引相同) ,又因为是同一对象,所以p2的键和值会覆盖掉p1
六、总结
如果你想要用自定义对象作为 HashMap的key ,为什么 hashCode、equals 方法都要实现?
相信你看完了四种情况,应该能说出个balabala...
那我们一起来balabala一下吧~
先利用 hashCode 方法计算出哈希值: 如果哈希值相同,在哈希表中计算出的索引肯定相同,会被放入一个桶中。这时候用 equals 方法查看是否是相同的对象。 如果是,用新的键和值覆盖掉旧的; 如果不是就用链地址法将对象串起来 如果哈希值不同,在哈希表中计算的索引也可能相同,也就是可能会被放入一个桶,也可能会被放入两个桶。 如果被放入一个桶中,同上一样,检查 equlas 方法; 如果放入两个桶中,则不需要查看是否 equals一般的开发需求会是第四种,想要用 p1和p2 作为 key 存储数据,会认为它们是同一个对象,它们是同一个 key ,也就只会存储一份数据。所以如果不同时实现 hashCode、equals 方法,会有图中的种种问题。
以上就是Java开发HashMap key必须实现hashCode equals方法原理的详细内容,更多关于Java开发HashMap key的资料请关注其它相关文章!
原文链接:https://juejin.cn/post/7183217019343339580
查看更多关于Java开发HashMap key必须实现hashCode equals方法原理的详细内容...