zoukankan      html  css  js  c++  java
  • HashMap源码分析(二):看完彻底了解HashMap

    上文讲到HashMap的增加方法,现在继续 上文链接

    HashMap在上一篇源码分析的文章中,如果使用put的时候如果元素数量超过threshold就会调用resize进行扩容

    1.扩容机制

    想要了解HashMap的扩容机制你要有这两个问题

    • 1.什么时候才需要扩容
    • 2.HashMap的扩容是什么

    在添加元素的时候如果超过threshold设置的阀值点就会进行扩容,简单的来说就是一个水壶容量是二升,然后这个时候已经满了但是你还要继续加水,咋办?换个大的。所以HashMap的扩容就和你这个水壶一样,水已经满了那我就在换个大的水壶继续加水。不过在你换水壶的时候是有很多条件的。

    在我看这个resize的源码的时候我也是一脸懵逼,最后请教了大佬得到的回答是因为1.8加入了红黑树比较麻烦可以看一下1.7的,然后我有去网上看了一下别人写的文章基本上都是基于1.7的resize。所以这里就看1.7的resize来分析。

    来看JDK1.7中resize的实现。

    复制操作是调用的transfer方法

    在1.7中的resize结合一下我们的小例子可以这样理解,去超市买一个大一点的水壶,然后把以前水壶里面的水给倒进新的水壶里面。再把我们当前的水壶的容量替换掉,告诉别人我的容量更大了。(强行比喻哈哈哈哈哈)

    1.7中的resize就是这么简单,那我们在看一下1.8中的resize(),这样再看就不会一脸懵逼了

    我在这里把1.8的resize方法分为两部分

    • 1.计算新的newCap(新的容量)和newThr(新阀值点)
    • 2.复制新的数组

    第一部分

    第二部分

    对比一下1.7

    • 1.7元素不需要更换位置。1.8元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置
    • 不需要像1.7一样重新计算hash

    2.删除

    删除的话就是首先先找到元素的位置,如果是链表就遍历链表找到元素之后删除。如果是用红黑树就遍历树然后找到之后做删除,树小于6的时候要转链表。

    删除方法:

    调用removeNode:

    3.查找元素

    查找方法,通过元素的Key找到Value。

    调用getNode()方法

    看完可以知道逻辑是先通过Key计算出索引的位置,然后先检查第一个节点看看是否是我们要的节点,如果不是在去查看是否死红黑树和链表。

    4.遍历

    我们通过下面几个例子来演示一下HashMap怎么遍历

    1.分别遍历Key和Values

     		for (String key:map.keySet()){
                System.out.println(key);
            }
            for (Object value : map.values()) {
                System.out.println(value);
            }
    

    2.迭代

     		Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> mapEntry = iterator.next();
                System.out.println(mapEntry.getKey() + "====" + mapEntry.getValue());
            }
    

    3.获取 key 集合

     	Set<String> keySet = map.keySet();
            for (String str : keySet) {
                System.out.println(str + "====" + map.get(str));
            }
    

    4.获取Entry 集合,遍历Entry 集合

    	Set<Map.Entry<String, Object>> entrySet = map.entrySet();
            for (Map.Entry<String, Object> entry : entrySet) {
                System.out.println(entry.getKey() + "====" + entry.getValue());
            }
    

    对比来说使用迭代的方式是最好的,也可以在迭代的时候对集合的元素进行删除

    总结

    基于JDK1.8的HashMap是由数组+链表+红黑树组成,当链表长度超过 8 时会自动转换成红黑树,当红黑树节点个数小于 6 时,又会转化成链表。相对于早期版本的 JDK HashMap 实现,新增了红黑树作为底层数据结构,在数据量较大且哈希碰撞较多时,能够极大的增加检索的效率。HashMap并不是线程安全的,支持K和V为null ,k重复会覆盖,V可以重复,还有一点HashMap遍历的数据不是有序的是无序的

  • 相关阅读:
    SGU 187 Twist and whirl
    伸展树---初步学习
    poj 2503 Babelfish
    sublime 3 phpfmt配置(大括号对齐)
    Linux Shell 错误: $' ': command not found错误解决
    redis 使用场景
    wireshake tcp 三次握手详解
    ip地址和子网掩码
    phpstorm 远程调式 php
    win10,ubuntu时间不对问题
  • 原文地址:https://www.cnblogs.com/Scramblecode/p/11205088.html
Copyright © 2011-2022 走看看