Java 散列存储详解及简单示例

作者:lqh 时间:2022-06-30 23:19:52 

Java 散列存储

Java中散列存储的数据结构主要是指HashSet、HashMap、LinkedHashSet、LinkedHashMap以及HashTable等。要理解Java中的散列存储机制,那么我们必须先理解两个方法:equals()和hashCode()。关于equals()方法以及其与“==”关系操作符的区别,我们在另一篇文章中已经说明了。而对于hashCode(),它是在Object类中定义的一个方法:


public native int hashCode();

这是一个返回int值的本地方法,在Object类中没有被实现。这个方法主要被应用于使用散列的数据结构中,配合基于散列的集合一起正常运行,例如,在向一个容器(我们假设是HashMap)中插入一个对象时,怎样判断容器中是否已经存在该对象了呢?由于容器中的元素可能成千上万,使用equals()方法依次进行比较是非常低效的。散列的价值在于速度,它将键保存在某处,以便能够很快找到。存储一组元素最快的数据结构是数组,所以使用它来存储键的信息(注意是键的信息,而非键本身)。但是因为数组不能调整容量,因此就有一个问题:我们希望在Map中保存数量不确定的值,但是如果键的数量被数组的容量限制了,该怎么办呢?

答案就是:数组不保存键本身,而是通过键对象生成一个数字,将其作为数组的下标,这个数字就是散列码(hashcode),由定义在Object中的、且可能由你的类覆盖的hashCode()方法生成。为解决数组容量被固定的问题,不同的键可以产生相同的下标,这种现象被称为冲突。于是,在容器中查询一个值的过程是:先通过hashCode()计算待插入对象的散列码,然后使用散列码查询数组。对于冲突的处理,常常是通过外部链接,即数组并不直接保存值,而是保存值的list,然后对list中的值进行线性查询,这部分查询自然会比较慢。但是,如果散列函数足够好的话,数组的每个位置就只有较少的值。因此,散列机制便可以快速地跳到数组的某个位置,只对很少的元素进行比较。这就是HashMap会如此快的原因,我们可以通过HashMap.put()方法体会到:


public V put(K key, V value) {
 if (table == EMPTY_TABLE) {
  inflateTable(threshold);
 }
 if (key == null)
  return putForNullKey(value);
 int hash = hash(key);
 int i = indexFor(hash, table.length);
 for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  Object k;
  if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
   V oldValue = e.value;
   e.value = value;
   e.recordAccess(this);
   return oldValue;
  }
 }

modCount++;
 addEntry(hash, key, value, i);
 return null;
}

其主要思想便是:在键不为空时,根据键对象获取到散列码hash,然后通过散列码得到数组的下标i。在table[i]所表示的list中进行迭代,通过equals()判断该键是否存在,如果存在,则用新的值更新旧的值,返回旧的值;否则将新的键值对添加到HashMap中。从这里可以看出,hashCode方法的存在是为了减少equals方法的调用次数,从而提高程序效率。

这里我们需要注意到:hashCode()并不需要总是能够返回唯一的标识码,但是equals()方法必须严格地判断两个对象是否相同。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

来源:http://blog.csdn.net/xiangwanpeng/article/details/52842629

标签:Java,散列存储
0
投稿

猜你喜欢

  • android点击无效验证的解决方法

    2022-02-28 03:55:08
  • java中的控制结构(if,循环)详解

    2022-05-13 19:18:59
  • springcloud微服务基于redis集群的单点登录实现解析

    2023-05-27 17:10:32
  • Java file类中renameTo方法操作实例

    2021-06-13 01:21:03
  • 安卓版微信小程序跳一跳辅助

    2022-08-30 13:44:20
  • 基于mybatis plus实现数据源动态添加、删除、切换,自定义数据源的示例代码

    2021-08-20 20:07:46
  • Jenkins一键打包部署SpringBoot应用

    2022-08-03 16:37:18
  • C# string格式的日期时间字符串转为DateTime类型的方法

    2022-04-07 09:34:30
  • Java使用Redis实现秒杀功能

    2023-04-11 11:26:54
  • 浅谈C#设计模式之工厂模式

    2021-12-17 16:06:48
  • java遍历读取xml文件内容

    2023-11-12 09:59:09
  • IDEA+Maven搭建Spring环境的详细教程

    2023-11-25 07:50:34
  • Java List转换成String数组几种实现方式详解

    2023-11-10 07:19:41
  • Spring Core动态代理的实现代码

    2021-12-11 03:40:54
  • C#连接ODBC数据源的方法

    2023-04-20 07:30:33
  • 安卓Android6.0权限动态获取操作示例

    2023-01-26 22:56:43
  • HighCharts图表控件在ASP.NET WebForm中的使用总结(全)

    2022-07-13 02:11:12
  • c# 类型的字段和方法设计建议

    2022-09-23 22:20:44
  • Golang+Android基于HttpURLConnection实现的文件上传功能示例

    2023-10-27 06:19:46
  • Java实现部门员工管理

    2021-07-21 21:40:41
  • asp之家 软件编程 m.aspxhome.com