jdk1.8--HashMap简单笔记

一、概述

1.1 jdk_1.8之前HashMap都是基于数组+链表实现 非线程安全的。

1.1

1.2 缺点:如果出现hash碰撞(桶entry碰撞),就会退化成单链表!查找时间从O(1)到O(n)。最好不要出现hash碰撞。

2.1 jdk_1.8之前后HashMap都是基于数组+链表+红黑树实现的 非线程安全的。


2.1

因为jdk_1.8之前出现桶碰撞, 在链表中查找数据会出现很大的性能损失。所以jdk_1.8之后当出现hash值冲突时, 如果链表node节点大于8时不再采用链表,转而使用红黑树代替链表!提高查找效率。

关于性能提升参考:http://blog.csdn.net/lc0817/article/details/48213435/



二、源码解析

1 字段解析(注释来自百度翻译  勿怪)

/**

*表中,第一次使用初始化,并调整其大小为

*必要。分配时,长度总是两个幂。

*我们也允许在某些操作中允许长度为零

*目前不需要的自举机构。)

*/

transient Node[]table;  这个就是上图中的 hash数组。



/ * *

*此映射中包含的键值映射的数量。

* /

transient int size; 个人觉得就是Node<k,v>节点数量

/ * *

*调整大小的下一个尺寸值(容量*负载因子)。

*

* @系列

* /

/ /(javadoc的描述是真实的在序列化。此外,如果尚未分配表数组,则字段保留初始数组容量,或零表示 default_initial_capacity。)

int threshold;  个人理解为扩容阀值 如果 size(node节点) 大于这个值是 则对table数组进行扩容。

float loadFactor;  装载因子

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 默认初始化数组大小为16

static final float DEFAULT_LOAD_FACTOR = 0.75f;   默认装载因

/ * *

*使用树的bin计数阈值,而不是列表

*仓。当添加一个元素到一个

* bin至少有这么多节点。值必须更大。

*大于2,至少应符合假设的8

*树搬迁转换回平原垃圾桶后

*收缩。

* /

static final int TREEIFY_THRESHOLD = 8; 链表最大长度 大于这个长度,链表转化为红黑树

2. 构造函数

相关自己可以看下源码

知道存储的数据大小时最好指定大小

3. 关于Node类型

Node<k,v>[] table;

Node<K,V> 是一个HashMap的一个静态内部类。他是实现于Map.Entry<k,v>

重要参数:

final int hash;  hash值 

final K key; 存储的key

V value;   存储的值

Node<k,v> next;   指向的下一个节点的地址

4 存储方法

public V put(K key, V value) {

return putVal(hash(key), key, value, false, true);

}


static final int hash(Object key) {

int h;

 //通过这里我们也就可以发现key是可以为null的,如果为空返回0也就是table[0]的位置。

    return (key ==null) ?0 : (h = key.hashCode()) ^ (h >>>16);

}


final V putVal(int hash, K key, V value, boolean onlyIfAbsent,

              boolean evict) {

Node[] tab; Node p; int n, i;

//将table赋值给 tab 如果tab为null或者长度为0 则重新去初始化table(注意在resize里面 由于 现在tab和table 指向的是同一个地址 所以也是初始化tab)

if ((tab =table) ==null || (n = tab.length) ==0)

     n = (tab = resize()).length;

//tab[i = (n -1) & hash] 这样写还是第一次见, 反正意思通过 (n -1) & hash 得到数组下标的值 为空的时候 就去创建一个新的节点并保存到那个下标((n -1) & hash)上去

if ((p = tab[i = (n -1) & hash]) ==null)

     tab[i] = newNode(hash, key, value, null);

else {

    //一旦不为空 所以就hash碰撞了。需要组成 链表或者树。

     Node e; K k;

   //如果发现hash值(下标) 和 将要存储的key 都是一致的, 注意:p是通过(p = tab[i = (n -1) &   hash]) 得到的  将这个值赋给e,  后面会对e执行是否覆盖value的操作。

     if (p.hash == hash &&((k = p.key) == key || (key !=null && key.equals(k))))

           e = p;

     else if (p instanceof TreeNode)

          //判断 节点是否是红黑树类型 如果是执行红黑插入操作。

           e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);

     else {

         //到这里说明链表存储的,则对链表进行循环依次向后查找

          for (int binCount =0; ; ++binCount) {

                //将p指向的下一个节点赋值给 e 如果为null这是链表的最后一个节点了 则将创建一个新节点赋值给p的下一个节点即(next)

                if ((e = p.next) ==null) {

                        p.next = newNode(hash, key, value, null);

//如果冲突节点达到8个,调用treeifyBin(tab, hash),这个treeifyBin首先回去判断当前hash表的长度,如果不足64的话,实际上就只进行resize,扩容table,如果已经达到64,那么才会将冲突项存储结构改为红黑树。  

                        if (binCount >=TREEIFY_THRESHOLD -1)// -1 for 1st

                                treeifyBin(tab, hash);

                       break;

           }

//当e 不等于空 且他的hash值和key等于要存储的hash值 和key时则结束循环 后面会判断是否对value覆盖

if (e.hash == hash && ((k = e.key) == key || (key !=null && key.equals(k))))

break;

               //把e赋给p继续循环

                p = e;

            }

}

//如果e不等于空说明数或者链表存在或者插入 hash值和key一样的节点了, 这里就是进行对value判断是否用新的值覆盖以前的值!

if (e !=null) {// existing mapping for key

            V oldValue = e.value;

           //判断是否修改已插入节点的value  

            if (!onlyIfAbsent || oldValue ==null)

e.value = value;

            afterNodeAccess(e);

            return oldValue;

        }

}

//插入新节点后,hashmap的结构调整次数+1

++modCount;

    if (++size >threshold) //判断节点大小是否大于扩容阀值大于就执行扩容

resize();

    afterNodeInsertion(evict);

return null;

}

作为第一次写文章,大量参考其他文章只是对部分做了点个人理解和 详细解释!

不到之处欢迎指正。

发现对代码支持很差呢!

参考:JDK1.8 HashMap源码分析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容