zoukankan      html  css  js  c++  java
  • HashMap的底层实现

    Jdk1.8之前:

    jdk1.8之前HashMap底层是数组跟链表,结合以前就是链表散列HashMap通过key的hashCode经过扰动函数处理的到hash值,然后通过(数组长度-1)&hash值判断当前元素存放的位置,如果当前元素存在的话,就判断该元素与要存入的元素的hash值以及key是否相同,如果相同直接覆盖,如果不相同就通过拉链法解决冲突。

    扰动函数是指的是HashMap的hash方法。使用hash方法也就是扰动函数是为了防止一些实现比较差的hashCode()方法换句话说使用扰动函数是可以减少碰撞。

    Jdk1.8的hash方法相比较于jdk1.7的hash方法更加简化,但是原理不变。

     static final int hash(Object key) {
     int h;
     // key.hashCode():返回散列值也就是hashcode
     // ^ :按位异或
     // >>>:⽆符号右移,忽略符号位,空位都以0补⻬
     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
     }

    对比一下Jdk1.7的HashMap的hash方法源码

    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);
    }

    相比于jdk1.8的hash方法,jdk1.7的hash方法的性能会比较差一点毕竟扰动了4次。

    所谓“拉链法”就是:将数组和链表相结合。就是创建一个链表数组,数组中每一各就是一个链表。若遇到哈希冲突,则将冲突的值加入到链表就行。

    jdk1.8之后

    相比较于之前的版本,jdk1.8之后在解决哈希冲突有了比较大的变化,当链表长度大于阈值(默认8)时候

     将链表转化为红黑树,减少搜索时间。

     TreeMap,TreeSet以及jdk之后的HashMap底层都用到了红黑树,红黑树是为了解决二叉树的缺陷,因为二叉树在某种情况会退化成一个线性结构。

     HashMap的长度为什么是2的幂次方

    为了能让HashMap存储高效,尽量减少碰撞,也就是把数据分配均匀,Hash值得范围值-2147483648到2147483647,前后加起来大概40亿的映射空间,只要哈希函数映射的比较松散均匀,一般很难出现碰撞,但是问题是40亿的数组 内存是放不下的所以这个散列值是不能直接拿来用的。用之前还要先做对数组长度的取模运算,得到的余数才能用来存放的位置也就是对应数组的下标。这个数组的计算方法"(n-1)&hash"。(n代表数组的长度)。这也就是解释了Hash的长度为什么是2的幂次方。

    这个算法如何设计的呢?

    我们首先可能会想到%取余的操作来实现。但是重点:“取余(%)会导致如果除数2的幂次方等价于与除数建议的与(&)操作(也就是说hash%length==hash&(length-1)的前提是length是2的n次方;”并且采用二进制位操作&相对于%能够提高运算效率,这就是解释了HashMap的长度为什么2的幂次方了

    hashMap多线程操作导致死循环的问题:

    主要原因在于并发的情况下的Rehash会造成元素之间造成循环链表,不过jdk1.8解决了这个问题,但是建议多线程的情况下使用HashMap,因为多线程下使用Hash还会造成数据丢失的情况。并发的情况下推荐使用ConcurrentHashMap。

    博客到此,分享一下我学习编程的途径希望大家循序渐进,共同进步:

    How2J Java教程:当下Java小白的引路人,以有趣和好理解的方式展示Java和Web的内容拥有当今流行的java路线。

    哔哩哔哩 (-)つロ 干杯~-bilibili中国最大的学习平台没有之一,拥有海量的资源有时间的小伙伴可以免去重金花钱培训。

    廖雪峰的官方网站廖雪峰,十年软件开发经验,业余产品经理,精通Java/Python/Ruby/Scheme/Objective C等,对开源框架有深入研究..

    菜鸟教程 - 学的不仅是技术,更是梦想!提供了编程的基础技术教程, 介绍了HTML、CSS、Javascript、Python,Java,Ruby,C,PHP , MySQL等各种编程语言的基础知识。

  • 相关阅读:
    案例------存储过程
    案例------冒泡排序
    案例------递归调用
    天气预报接口api(中国天气网)
    【转】ubuntu64,ndk-r9 编译 ffmpeg 2.1.1的config文件
    android权限大全
    JNI 回调小记
    java设置环境变量小工具
    bootstrap之双日历时间段选择控件—daterangepicker(汉化版)
    一个 bootstrap 弹出框插件
  • 原文地址:https://www.cnblogs.com/jinronga/p/12466601.html
Copyright © 2011-2022 走看看