1.HashMap的内部实现机制

HashMap是对数据结构中哈希表(Hash Table)的实现,Hash表又叫散列表。Hash表是根据关键码Key来访问其对应的值Value的数据结构,它通过一个映射函数把关键码映射到表中一个位置来访问该位置的值,从而加快查找的速度。这个映射函数叫做Hash函数,存放记录的数组叫做Hash表。

在Java中,HashMap的内部实现结合了链表和数组的优势,链接节点的数据结构是Entry<k,v>,每个Entry对象的内部又含有指向下一个Entry类型对象的引用,如以下代码所示:

static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next; //Entry类型内部有一个自己类型的引用,指向下一个Entry
final int hash;
...
}

在HashMap的构造函数中可以看到,Entry表被申明为了数组,如以下代码所示:

 public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table = new Entry[DEFAULT_INITIAL_CAPACITY];
init();
}

在以上构造函数中,默认的DEFAULT_INITIAL_CAPACITY值为16,DEFAULT_LOAD_FACTOR的值为0.75。

当put一个元素到HashMap中去时,其内部实现如下:

public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
...
}

可以看到put函数中用一个hash函数来得到哈希值,需要指出的是,HashTable在实现时直接用了hashCode作为哈希值,因此采用HashMap代替HashTable有一定的优化。

put函数中用到的两个函数hash和indexFor其实现分别如下:

static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
     /**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
return h & (length-1);
}

至于hash函数为什么这样设计,这涉及到具体哈希函数的设计问题了,需要考虑的是哈希算法的时间复杂度,同时尽量使得数组上每个位置都有值,求得时间和空间的最优。

indexFor函数则用了一个很巧妙的与运算将index值限制在了length-1之内。

当然,hash函数存在冲突的情况,同一个key对应的hash值可能相同,这时候hash值相同的元素就会用链接进行存储,HashMap的get方法在获取value的时候会对链表进行遍历,把key值相匹配的value取出来。

2.Hash的实现

主要是哈希算法和冲突的解决。

3.什么时候ReHash

在介绍HashMap的内部实现机制时提到了两个参数,DEFAULT_INITIAL_CAPACITY和DEFAULT_LOAD_FACTOR,DEFAULT_INITIAL_CAPACITY是table数组的容量,DEFAULT_LOAD_FACTOR则是为了最大程度避免哈希冲突,提高HashMap效率而设置的一个影响因子,将其乘以DEFAULT_INITIAL_CAPACITY就得到了一个阈值threshold,当HashMap的容量达到threshold时就需要进行扩容,这个时候就要进行ReHash操作了,可以看到下面addEntry函数的实现,当size达到threshold时会调用resize函数进行扩容。

void addEntry(int hash, K key, V value, int bucketIndex) {
ntry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}

在扩容的过程中需要进行ReHash操作,而这是非常耗时的,在实际中应该尽量避免。

(原创文章,转载请注明作者schbook:seekerxu@163.com)

HashMap的内部实现机制,Hash是怎样实现的,什么时候ReHash的更多相关文章

  1. 【转】Java学习---HashMap和HashSet的内部工作机制

    [原文]https://www.toutiao.com/i6593863882484220430/ HashMap和HashSet的内部工作机制 HashMap 和 HashSet 内部是如何工作的? ...

  2. Windows程序内部运行机制 转自http://www.cnblogs.com/zhili/p/WinMain.html

    一.引言 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制,然而在.NET平台下,创建一个Windows桌面程序,只需要简单地选择Windows窗体应用程序 ...

  3. 关于js内部运行机制的一本好书

    读<单页Web应用一书>,第二章讲了js内部运行机制,感觉棒极了.之前读<你不知道的js>,看的云里雾里,似懂非懂.没想到单页Web一书将此内容讲的如此通俗易懂,好多困惑已久的 ...

  4. 深入浅出话VC++(1)——Windows程序内部运行机制

    一.引言 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制,然而在.NET平台下,创建一个Windows桌面程序,只需要简单地选择Windows窗体应用程序 ...

  5. 深入理解ASP.NET的内部运行机制(转)

    WebForms和WebServices作为.NET平台构建Web程序的两大利器,以其开发简单.易于部署的特点得到了广泛的应用,但殊不知微软公司在背后为我们做了大量的基础性工作,以至于我们开发人员只需 ...

  6. IIS 内部运行机制及Asp.Net执行过程详解

    一直以来对一个Asp.net页面穿过IIS后就返回给浏览器一个HTML页面感觉很是神奇.虽然做技术这么长时间了,也曾经大致了解过一点来龙去脉,但是如果你真的问起我比较详细的过程,我还真的回答不上来,好 ...

  7. Java动态绑定的内部实现机制

     JAVA虚拟机调用一个类方法时,它会基于对象引用的类型(通常在编译时可知)来选择所调用的方法.相反,当虚拟机调用一个实例方法时,它会基于对象实际的类型(只能在运行时得知)来选择所调用的方法,这就是动 ...

  8. spring 内部工作机制(二)

    本章节讲Spring容器从加载配置文件到创建出一个完整Bean的作业流程及参与的角色. Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表, ...

  9. Spark内部执行机制

    Spark内部执行机制 1.1 内部执行流程 如下图1为分布式集群上spark应用程序的一般执行框架.主要由sparkcontext(spark上下文).cluster manager(资源管理器)和 ...

随机推荐

  1. Thinkphp 3.2.2 验证码check_verify方法,只能验证一次

    问题: Thinkphp 3.2.2 验证码check_verify方法,只能验证一次. function check_verify($code, $id = ''){ $verify = \Thin ...

  2. css兼容性大坑

    一. \:选择IE6+//区分 IE 8(不实用) .title{ color:yellow\0; color: red\9\0;} \9在 IE 6及其以上都可以识别(但是 IE11不识别 ,IE ...

  3. MFC双缓存技术代码

    屏蔽背景刷新,在View中添加对WM_ERASEBKGND的响应,直接返回TRUE: BOOL CTEMV1View::OnEraseBkgnd(CDC* pDC) { // TODO: 在此添加消息 ...

  4. intellij idea Maven 创建项目时出现的一些问题

    1.关于maven仓库的问题 在下载资源的时候特别慢,原因是因为天朝的网络你们都懂的.解决方式使用国内镜像,原本可以用的OSChina的镜像,由于其服务器关闭,现在无法使用. 解决方案是使用阿里云的m ...

  5. ng-repeat 里 使用ng-show ng-hide出现闪动

    在项目中使用ng-repeat在表格中循环输出一组数据的时候,需要对表格中的每一列(每一列为数组的一个元素--对象)添加控制按钮. 列表样式 我的期望是 初始化 ----每一行不可编辑,保存按钮是隐藏 ...

  6. 我的LaTeX中文文档模板

    中文LaTeX处理模板 环境MiTex内核 编辑环境WinEdit 源码如下: \documentclass[a4paper,12pt]{article} \usepackage{CJK} %设定字号 ...

  7. django 强制登录最佳实践

    参考: https://python-programming.courses/recipes/django-require-authentication-pages/ 即通过中间件来做AOP拦截.不用 ...

  8. kill命令

    *杀死进程最安全的方法是单纯使用kill命令,不加修饰符,不带标志.   首先使用ps -ef命令确定要杀死进程的PID,然后输入以下命令:   # kill -pid   注释:标准的kill命令通 ...

  9. 设计模式--原型模式Prototype(创建型)

    一.原型模式 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.原型模式实现的关键就是实现Clone函数,还需要实现深拷贝. 二.UML类图 三.例子 //父类 class Resume ...

  10. selenium Remote Server 实现原理

    selenium作为一个出色的web automation框架,被越来越多的企业采用究其原因,框架设计的比较remarkable, 作为一个开源的框架,能够开辟出一套协议,以至于针对app测试的app ...