详解Java中用于查找对象哈希码值的hashCode()函数

作者:冯立彬 时间:2023-09-17 02:52:19 

理解
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。
虽然,每个Java类都包含hashCode() 函数。但是,仅仅当创建并某个“类的散列表”(关于“散列表”见下面说明)时,该类的hashCode() 才有用(作用是:确定该类的每一个对象在散列表中的位置;其它情况下(例如,创建类的单个对象,或者创建类的对象数组等等),类的hashCode() 没有作用。
上面的散列表,指的是:Java集合中本质是散列表的类,如HashMap,Hashtable,HashSet。
也就是说:hashCode() 在散列表中才有用,在其它情况下没用。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
我们都知道,散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!
散列表的本质是通过数组实现的。当我们要获取散列表中的某个“值”时,实际上是要获取数组中的某个位置的元素。而数组的位置,就是通过“键”来获取的;更进一步说,数组的位置,是通过“键”对应的散列码计算得到的。
下面,我们以HashSet为例,来深入说明hashCode()的作用。
假设,HashSet中已经有1000个元素。当插入第1001个元素时,需要怎么处理?因为HashSet是Set集合,它允许有重复元素。
“将第1001个元素逐个的和前面1000个元素进行比较”?显然,这个效率是相等低下的。散列表很好的解决了这个问题,它根据元素的散列码计算出元素在散列表中的位置,然后将元素插入该位置即可。对于相同的元素,自然是只保存了一个。
由此可知,若两个元素相等,它们的散列码一定相等;但反过来确不一定。在散列表中,
1、如果两个对象相等,那么它们的hashCode()值一定要相同;
2、如果两个对象hashCode()相等,它们并不一定相等。
注意:这是在散列表中的情况。在非散列表中一定如此!

示例
我们来看一个具体的示例吧,


public class HashTest {
 private int i;

public int getI() {
   return i;
 }

public void setI(int i) {
   this.i = i;
 }

public int hashCode() {
   return i % 10;
 }

public final static void main(String[] args) {
   HashTest a = new HashTest();
   HashTest b = new HashTest();
   a.setI(1);
   b.setI(1);
   Set<HashTest> set = new HashSet<HashTest>();
   set.add(a);
   set.add(b);
   System.out.println(a.hashCode() == b.hashCode());
   System.out.println(a.equals(b));
   System.out.println(set);
 }
}

这个输出的结果:


true
false
[com.ubs.sae.test.HashTest@1, com.ubs.sae.test.HashTest@1]

以上这个示例,我们只是重写了hashCode方法,从上面的结果可以看出,虽然两个对象的hashCode相等,但是实际上两个对象并不是相等;,我们没有重写equals方法,那么就会调用object默认的equals方法,是比较两个对象的引用是不是相同,显示这是两个不同的对象,两个对象的引用肯定是不定的。这里我们将生成的对象放到了HashSet中,而HashSet中只能够存放唯一的对象,也就是相同的(适用于equals方法)的对象只会存放一个,但是这里实际上是两个对象a,b都被放到了HashSet中,这样HashSet就失去了他本身的意义了。
此时我们把equals方法给加上:


public class HashTest {
 private int i;

public int getI() {
   return i;
 }

public void setI(int i) {
   this.i = i;
 }

<span style="color:#3366FF;"><strong>public boolean equals(Object object) {
   if (object == null) {
     return false;
   }
   if (object == this) {
     return true;
   }
   if (!(object instanceof HashTest)) {
     return false;
   }
   HashTest other = (HashTest) object;
   if (other.getI() == this.getI()) {
     return true;
   }
   return false;
 }</strong></span>

public int hashCode() {
   return i % 10;
 }

public final static void main(String[] args) {
   HashTest a = new HashTest();
   HashTest b = new HashTest();
   a.setI(1);
   b.setI(1);
   Set<HashTest> set = new HashSet<HashTest>();
   set.add(a);
   set.add(b);
   System.out.println(a.hashCode() == b.hashCode());
   System.out.println(a.equals(b));
   System.out.println(set);
 }
}

此时得到的结果就会如下:


true
true
[com.ubs.sae.test.HashTest@1]

从结果我们可以看出,现在两个对象就完全相等了,HashSet中也只存放了一份对象。

总结
1、hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;

2、如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;

3、如果对象的equals方法被重写,那么对象的hashCode也尽量重写,并且产生hashCode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;

4、两个对象的hashCode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.Object) 方法,只能够说明这两个对象在散列存储结构中,如Hashtable,他们“存放在同一个篮子里”。

标签:Java,hashCode
0
投稿

猜你喜欢

  • android开发权限询问的示例代码

    2021-07-29 00:16:26
  • eclipse 中的javac命令与java命令

    2023-08-19 14:16:57
  • Spring Boot + Mybatis 实现动态数据源案例分析

    2023-05-15 12:13:47
  • 浅析JAVA中的内存结构、重载、this与继承

    2023-09-24 19:15:07
  • Android实现图片自动轮播并且支持手势左右无限滑动

    2021-11-04 22:56:46
  • C#虚方法的声明和使用实例教程

    2022-09-26 16:07:55
  • java实现微信扫码支付功能

    2023-11-09 18:38:08
  • 详解Java实现设计模式之责任链模式

    2023-11-08 10:32:07
  • Android Studio设置或修改Android SDK路径方法

    2023-11-07 17:22:10
  • SpringBoot Entity中枚举类型详细使用介绍

    2023-11-11 00:30:52
  • SpringBoot中获取微信用户信息的方法

    2023-05-26 21:40:55
  • Mybatis-Plus支持GBase8s分页查询的实现示例

    2021-11-21 14:33:30
  • Android百度地图实现搜索和定位及自定义图标绘制并点击时弹出泡泡

    2023-08-30 21:30:38
  • c#实现多线程局域网聊天系统

    2022-12-01 23:34:25
  • Java实体类不要使用基本类型的知识点总结

    2023-02-21 10:04:49
  • Java实现简易界面通讯录

    2023-02-09 20:12:59
  • Java接口DAO模式代码原理及应用详解

    2023-06-21 05:29:04
  • android 软键盘的POPUP布局的问题解决

    2022-03-22 17:53:30
  • C#多线程系列之资源池限制

    2022-01-02 17:11:04
  • mybatis中foreach嵌套if标签方式

    2023-11-20 23:11:05
  • asp之家 软件编程 m.aspxhome.com