好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Java开发HashMap key必须实现hashCode equals方法原理

一、问题引入

平时在开发中,相信你多多少少都使用过 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方法原理的详细内容...

  阅读:16次