Java基础之HashCode解读

前言

在Object类中,提供了一个native方法,public native int hashCode(),该方法的返回值类型是int类型。

Hash的概念 

Hash,一般翻译成“散列”,或者直译为“哈希”,把任意长度的输入x,通过散列算法f(x),变成固定的长度输出,该输出值就是散列码。

1.如果结构中存在和输入值K相等的记录,则必定在f(K)的存储位置上。

2.对应关系f称为散列函数,按这个事先建立的表称为散列表,散列表由多个bucket构成,每个bucket可以存储多个散列码的位置。

3.对于两个不同的输入值K1、K2,可能得到的散列码不同,即,K1 != K2  → f(K1) == f(K2) ,这种现象称为碰撞。

4.在同一个散列函数中,如果两个输入值K1、K2,得到的散列码 f(K1) != f(K2),那么K1与K2必定不相同。

HashCode的概念

HashCode是JDK根据对象的地址,或者字符串或者数字算出来int类型的值,这个值我们称为HashCode,换一句话来说,上述提到通过散列函数得出的散列码就是HashCode。

HashCode的几个重要的性质:

1.一致性,在Java应用程序执行期间,在同一个Hash算法下,同一个对象的HashCode必定永远相同。

2.在同一个Hash算法下,当两个对象的HashCode相同,两个对象的equals方法也不一定相同,只能说明在散列的数据结构中,他们存储在同一个位置。

3.如果两个对象的equals方法相等,那么他们的HashCode必定相同。

4.重写了Object类中的equals方法,HashCode也尽量重写。

HashCode的作用

HashCode的存在就为了查找的快捷,因为HashCode是用来在散列存储结构中确定对象的存储地址,即:使用hashcode来代表对象在hash表中的位置。

举个例子,我们在内存中要维护1-10000一万个数字,我们可以采用数组,存储,当我存第9001的数字时,需要去遍历前面9000个数字,判断是否是重复,这样的操作会极为耗时,在使用hashcode,假设有200个bucket,hash表中有200个位置,比如要维护数字1,取到的hashcode为1,那就放在第一个bucket中,依次类推,当存储500时,hashcode同样为1,假设第一个位置已经有10个元素,那么只要比较10次,如果没

有相同,那就放在这个bucket中。

因此,HashCode就是为了查找便捷而生。

equals方法和hashcode方法的联系

通过上面的举例,在散列数据结构的查找中,我们先得出hashcode知道具体的位置,如果该位置上有多个元素,那么逐一比对,即调用equals方法,因此证明了以上提到的观点,

1.hashcode相同的两个对象,两个对象不一定相同,只能说明两个对象在散列数据结构中存放在同一个位置,

2.equals相同的两个对象,他们的hashcode必然相同。

为什么重写Object类中的equals方法尽量重写Object类中的hashcode方法

 1 public class HashCodeTest {
 2 
 3     private Long id;
 4     private String name;
 5 
 6     public Long getId() {
 7         return id;
 8     }
 9     @Override
10     public boolean equals(Object obj){
11         if(obj instanceof HashCodeTest) {
12             HashCodeTest t = (HashCodeTest)obj;
13             if(id.equals(t.id) && name.equals(t.name())) {
14                 return true;
15             }
16         }
17         return false;
18     }
19 }

我们重写了Object类中的equals方法,只有两个对象类型相同,并且两个成员属性相同,两个对象才认为是相等。

1 public static void main(String[] args) {
2         System.out.println(new HashCodeTest(1L,"tom").hashCode());
3         System.out.println(new HashCodeTest(1L,"tom").hashCode());
4         System.out.println(new HashCodeTest(1L,"tom").hashCode());
5         System.out.println(new HashCodeTest(1L,"tom").hashCode());
6         System.out.println(new HashCodeTest(1L,"tom").hashCode());
7 }

打印出来的结果是:

1528637575
1190524793
472654579
26117480
870698190

 equals方法中希望id和name都完全相同则返回true,上述new HashCodeTest中的id和name均相同,如果重写hashcode,就违背了【两个对象的equals相同,hashcode必然相同】的原则,那么我们应该如何处理呢?

很简单,我们自定义一个id和name保持唯一的算法用来重写HashCode方法。

下期预告

这段时间花了大量的精力聊树结构,聊散列结构,都是为了 下期对HashMap原代码的解读打下坚实的基础。谢谢关注。

原文地址:https://www.cnblogs.com/sunshine798798/p/9191482.html