Java HashMap笔记之一:基本原理

转载 2017年07月29日 09:24:01
摘要: Java中的HashMap是一种简单易用而且高效强大的数据结构,在开发过程中经常使用。这里总结下HashMap的基本原理。HashMap默认内部数组大小?HashMap内部数组为16(JDK7和JDK8都是)。HashMap Default Capacity如果初始 ...

Java中的HashMap是一种简单易用而且高效强大的数据结构,在开发过程中经常使用。这里总结下HashMap的基本原理。

HashMap默认内部数组大小?

HashMap内部数组为16(JDK7和JDK8都是)。

HashMap Default Capacity

如果初始化大小为33,内部数组真实大小是多少?

内部数组真实大小是64。HashMap带有initialCapacity参数的构造方法会调用tableSizeFor方法进行设置,结果为大于等于initialCapacity的最小的2的幂。以下代码都是JDK8的源码,JDK7类似。

JDK8生成数组大小方法

HashMap内部数组大小为什么是2的幂?

HashMap充分利用了二进制中1的信息,通过hash(key) & (capacity - 1)获取内部数组中的索引位置。当capacity为2的幂的时候,capacity - 1的二进制的1的个数是最多,可以最充分的利用数组。

比如capacity = 17的时候,capacity - 1 = 16 = 0x0001 0000,这样,hash & (capacity - 1)只能有2个值,0x0000 0000 和0x0001 0000,为了最方便和充分的使用数组索引,数组的大小最好是2的幂。

HashMap通过Hash获取索引

HashMap什么时候开辟内部数组内存?

HashMap在new的时候只是进行内部参数的初始化,但是不会对数组进行内存申请,只有在第一次put操作的时候才会开辟内存,也就是一般说的lazy模式。

HashMap无参构造方法

可以看到在new的时候没有进行任何的内存申请的操作,而是在put的时候判断内部数组是否为空,如果为空,先进行初始化再put元素。以下代码为JDK7的源码,相对JDK8的源码比较容易理解,JDK8中直接调用resize方法申请内存。

PS: inflate是打气筒,使膨胀的意思,方法名称非常形象。

HashMap为什么要扩容?

索引(index of hash(key))相同的节点会存储在内部数组相同的索引中,当数据量越来越大的时候,相同索引的节点会越来越多,导致遍历的时间会越来越久。扩容可以重新计算索引值,减少相同索引节点个数和索引时间,也就是说用空间来换取时间。

假设数组大小为16,hash值为1和17的节点都会在table[1]中,当数组大小扩容到32的时候,hash值为1的节点仍然在table[1]中,hash为17的节点会被分配到table[17]中,这样table[1]中的节点个数会变少。

HashMap何时进行扩容?

HashMap除了维护内部数组大小capacity外,还会维护loadFactor(默认为0.75),当put的时候元素数量大于等于capacity * loadFactor时会进行扩容。比如capacity=16,loadFactor=0.75,当第12(16*0.75=12)个元素put的时候,会进行扩容resize操作,扩展到原来capacity的2倍,因为之前是2的幂,所以扩容后仍然是2的幂。以下代码为JDK7的源码,在调用addEntry过程中将参数传到resize方法中,JDK8中则是在resize内部进行调整。最终效果是一致的。

HashMap Default LoadFactor

JDK7 put value

JDK7 resize in addEntry

JDK7和JDK8实现HashMap的区别?

  • JDK7使用数组+链表方式实现,索引相同的key在相同的链表中,新增加的key会加到链表的最后

  • JDK8使用数组+链表/红黑树的方式实现,在红黑树中的搜索时间是O(logN),好于链表的O(N)。链表和红黑树的转换规则如下:

  • 如果链表的长度超过8个,链表会转化为红黑树

  • 如果红黑树节点的个数少于6个,红黑树会转化为链表

小结

HashMap使用虽然简单,如果理解实现可以更好的利用内部特性,并借鉴设计思路。

面试中HashMap的工作原理

HashMap的工作原理 这篇文章极好,还有一些其它的东西,说的也很透彻。 详情,请点击: http://www.importnew.com/7099.ht...
  • paincupid
  • paincupid
  • 2015年08月17日 00:33
  • 1395

[Java基础要义] HashMap的设计原理和实现分析

读完本文,你会了解到: 1. HashMap的设计思路和内部结构组成 2. HashMap中的一些概念: 什么是阀值?为什么会有阀值?什么是加载因子?它们有什么作用? ...
  • u010349169
  • u010349169
  • 2014年11月30日 14:07
  • 7896

HashMap笔试面试题汇总解析

在笔试和面试的过程中,Java集合框架毫无疑问是考察的重点,貌似面试官对这都情有独钟,而有关HashMap的考察更是重中之重和难点,一个小小的HashMap不仅能反应出你对Java集合的掌握程度,更能...
  • song19890528
  • song19890528
  • 2013年11月22日 21:01
  • 8338

Java学习笔记(2) java基本原理概述

Java基本原理 首次调用 [从物理到内存] –> Interpreter 校验 再次调用 [从内存加载] 改变内容:runtime stop -> restart (冷部署) JVM:Jav...
  • tuzkimo
  • tuzkimo
  • 2015年04月19日 14:44
  • 155

【图解JDK源码】HashMap的基本原理与它的线程安全性

1. 前言能用图说清楚的,就坚决不用代码。能用代码撸清楚的,就坚决不写解释(不是不写注释哦)。2. 数据结构HashMap内部通过维护一个Entry数组(变量为table),来实现其基本功能,而Ent...
  • t894690230
  • t894690230
  • 2016年05月05日 18:06
  • 818

HashMap的基本原理与它的线程安全性

http://blog.csdn.net/t894690230/article/details/51323946 1. 前言 能用图说清楚的,就坚决不用代码。能用代码撸清楚的,就坚...
  • z69183787
  • z69183787
  • 2017年04月11日 15:45
  • 557

机器学习笔记:Fisher Vector基本原理与用法

近期在看的动作识别相关的工作中fisher vector及其改进版本被广泛的应用,因此打算从Fisher Vector开始入手整理相关知识。 参考的博客内容: http://blog.csdn...
  • wzmsltw
  • wzmsltw
  • 2016年07月27日 22:20
  • 7480

行为识别笔记:Stacked Fisher Vector基本原理

Stacked Fisher Vector是Xiaojiang Peng 在“Action Recognition with Stacked Fisher Vectors”一文中提出的用于动作识别的算...
  • wzmsltw
  • wzmsltw
  • 2016年07月28日 11:49
  • 2826

XSS学习笔记(一) 概念、基本原理、简单实例及危害

概念         跨站脚本(Cross-Site Scripting,XSS) 发生在目标网站中目标用户的浏览器层面上,当用户浏览器渲染整个HTML文档的过程中出现了不被预期的脚本指令并执行时,...
  • amosilin
  • amosilin
  • 2016年04月06日 00:40
  • 1606

socket网络编程复习笔记(一):套接字基本原理(上)

1.网络编程为何物?我们学习C语言时,一般都是从printf函数和scanf函数进行控制台输入输出开始的。控制台的输入输出和文件的输入输出非常类似。而网络编程,其实也与文件的输入输出十分相像,所以学起...
  • Meditator_hkx
  • Meditator_hkx
  • 2015年10月26日 13:20
  • 1056
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java HashMap笔记之一:基本原理
举报原因:
原因补充:

(最多只允许输入30个字)