HashMap存储结构

HashMap中数据的存储是由数组与链表一起实现的

数组寻址非常容易,其时间复杂度为O(1),但是当要插入或删除数据时,时间复杂度就会变为O(n)。链表插入和删除操作的内存复杂度为O(1),但是寻址操作的复杂度却是O(n)。HashMap结合两者的优点,即寻址,插入删除都快。

HashMap中定义了一个Entry类的数组table,    Entry<K,V>[] table;    数组table中存储的是Entry对象(也是Entry链表的头结点)。

Entry对象中保存的是Key-Value对。

其中数组table被称作buckets,每个数组节点则是一个bucket(可以构成一个链表)

capacity指的是buckets的容量,也即数组的大小,默认capacity大小如下

    /**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 16;

load factor是衡量buckets填满程度的比例,默认load factor大小如下

    /**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;

当buckets中entry数量大于capacity*loadfactor时就要把capacity扩充为原来的两倍。

HashMap中方法

添加键值对put(K key, V value)方法

实现流程如下:

进行key是否为null的判断,如果key==null ,放置在数组table的0号位置,即table[0]。

若key不为null,由key的hashCode计算相应的hash值,进而得到该key对应的数组table的下标i。

判断table[i] 是否为null(不包含任何键值对),若是则创建该键值对的Entry对象,添加至table[i]。

若table[i]不为null,遍历table[i]链表中的每个Entry对象,若该链表中已包含key,则覆盖其value。若该链表中不包含key,则创建该键值对的Entry对象并添加至链表头部。

实现代码如下:

public V put(K key, V value) {
// HashMap允许存放null键和null值。
// 当key为null时,调用putForNullKey方法,将value放置在数组table第一个位置。
if (key == null)
return putForNullKey(value); // 根据key的hashCode计算hash值。
int hash = hash(key.hashCode());
// 由hash值求得key对应table的下标。
int i = indexFor(hash, table.length); // 如果 i 索引处的 Entry 不为 null,遍历table[i]链表的每一个Entry对象
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
// 如果链表中已有键值key,则新的value覆盖原来的,并返回原来的value
// 判断为同一个键值的方法是,hash值相同,且key相同
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
} modCount++;
// 若table[i]为null,则创建key,value的Entry对象,并添加至table[i]处
// 若table[i]链表中没有键值key,则创建key,value的Entry对象,并添加至table[i]处
addEntry(hash, key, value, i);
return null;
}

addEntry()方法

void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length); //扩容操作,将数据元素重新计算位置后放入newTable中,链表的顺序与之前的顺序相反
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
} createEntry(hash, key, value, bucketIndex);
}
void createEntry(int hash, K key, V value, int bucketIndex) {
// 若table[i]不为null,则e指向table[i]链表的第一个元素
Entry<K,V> e = table[bucketIndex];
// 新的Entry对象添加至table[i]的表头
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}

get()方法

计算hash值,然后调用indexFor()方法得到该key在table中的存储位置,得到该位置的单链表,遍历列表找到key和指定key内容相等的Entry,返回entry.value值

实现代码如下:

public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}

HashMap的resize

当hashmap中的元素越来越多的时候,碰撞的几率也就越来越高(因为数组的长度是固定的),所以为了提高查询的效率,就要对hashmap的数组进行扩容,数组扩容这个操作也会出现在ArrayList中,所以这是一个通用的操作,很多人对它的性能表示过怀疑,不过想想我们的“均摊”原理,就释然了,而在hashmap数组扩容之后,最消耗性能的点就出现了:原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize。

那么hashmap什么时候进行扩容呢?当hashmap中的元素个数超过数组大小*loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,也就是说,默认情况下,数组大小为16,那么当hashmap中元素个数超过16*0.75=12的时候,就把数组的大小扩展为2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知hashmap中元素的个数,那么预设元素的个数能够有效的提高hashmap的性能。比如说,我们有1000个元素new HashMap(1000), 但是理论上来讲new HashMap(1024)更合适,不过上面annegu已经说过,即使是1000,hashmap也自动会将其设置为1024。 但是new HashMap(1024)还不是更合适的,因为0.75*1000 < 1000, 也就是说为了让0.75 * size > 1000, 我们必须这样new HashMap(2048)才最合适,既考虑了&的问题,也避免了resize的问题。

Java HashMap原理的更多相关文章

  1. Java:HashMap原理与设计缘由

    前言 Java中使用最多的数据结构基本就是ArrayList和HashMap,HashMap的原理也常常出现在各种面试题中,本文就HashMap的设计与设计缘由作出一一讲解,并解答面试常见的一些问题. ...

  2. java - HashMap原理及实现 (转)

    众所周知,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry.这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干. HashMap ...

  3. HashMap的原理与实 无锁队列的实现Java HashMap的死循环 red black tree

    http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html https://zh.wikipedia.org/wiki/%E7%BA ...

  4. Java HashMap工作原理及实现

    Java HashMap工作原理及实现 2016/03/20 | 分类: 基础技术 | 0 条评论 | 标签: HASHMAP 分享到:3 原文出处: Yikun 1. 概述 从本文你可以学习到: 什 ...

  5. Java基础-hashMap原理剖析

    Java基础-hashMap原理剖析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   一.什么是哈希(Hash) 答:Hash就是散列,即把对象打散.举个例子,有100000条数 ...

  6. Hash算法及java HashMap底层实现原理理解(含jdk 1.7以及jdk 1.8)

    现在很多公司面试都喜欢问java的HashMap原理,特在此整理相关原理及实现,主要还是因为很多开发集合框架都不甚理解,更不要说各种其他数据结构了,所以造成面子造飞机,进去拧螺丝. 1.哈希表结构的优 ...

  7. Java HashMap实现原理分析

    参考链接:https://www.cnblogs.com/xiarongjin/p/8310011.html 1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是 ...

  8. java中HashMap原理?

    参考:https://www.cnblogs.com/yuanblog/p/4441017.html(推荐) https://blog.csdn.net/a745233700/article/deta ...

  9. Java HashMap工作原理:不仅仅是HashMap

    前言: 几乎所有java程序员都用过hashMap,但会用不一定会说. 近年来hashMap是非常常见的面试题,如何为自己的回答加分?需要从理解开始. "你用过hashMap吗?" ...

随机推荐

  1. iOS UI-常用控件

    #import "ViewController.h" @interface ViewController ()<UITextFieldDelegate> // 标题标签 ...

  2. SQL优化(SQL TUNING)可大幅提升性能的实战技巧之一——让计划沿着索引跑

    我们进行SQL优化时,经常会碰到对大量数据集进行排序,然后从排序后的集合取前部分结果的需求,这种情况下,当我们按照常规思路去写SQL时,系统会先读取过滤获得所有集合,然后进行排序,再从排序结果取出极少 ...

  3. httpclient 连接路由

    http路由 httpclient能够直接或通过路由建立连接到目标主机,这会涉及多个中间连接,也被称为跳. Httpclient区分路由和普通连接,通道和分层. 通道连接到目标主机的多个中间代理的使用 ...

  4. learning uboot bootargs panic parameter

    By passing the kernel panic parameter, the system automatically resets after 3 seconds when kernel p ...

  5. CSS中的长度单位及颜色表示

       CSS中的长度单位及颜色表示 长度单位: px:像素,绝对单位 em:相对单位,如果用于font-size属性本身,则是相对于父元素的font-size.若用于其他属性(width,height ...

  6. 反向-代理 nginx for Mac 的配置以及使用

       反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端 ...

  7. 三个安装,手机看VIP电影。写给亲爱的学习

    三个安装,看VIP电影. 市场安装firefox 安装Tempermonkey 打开firefox,点击右上角的三个点,点击附加组件 继续点击浏览全部firefox附加组件 在上面的搜索框输入 tam ...

  8. 小知识,用myeclipes找jar

    有些时候,换台电脑就换了一个框架的版本,找对应的jar是一件非常麻烦的事. 我们可以使用myeclipes快速得到我们想要的jar 首先新建一个项目,然后使用myeclipes的自动生成框架技术,生成 ...

  9. JQuery, Silverlight 公用WCF

    WCF web.config配置: <?xml version="1.0"?> <configuration> <system.web> < ...

  10. Java Socket 实现HTTP服务器核心

    原文链接:http://www.ihuxu.com/p/235.html   首先了解下HTTP协议: wikiPedia的说明很好,在此不重复了.链接:http://zh.wikipedia.org ...