要了解HashMap的底层实现原理,我们首先要对HashMap的部分底层源码进行分析

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable

我们可以看出HashMap继承了AbstractMap,实现了Map,Cloneable,Serializable接口。

 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

HashMap的默认初始容量(必须是2的幂),它的值是1左移4位,也就是16

static final int MAXIMUM_CAPACITY = 1 << 30;

HashMap的最大容量,如果任何一个带参数的构造函数指定了较大的值,就会使用它来比较,而且值必须是2的幂,并且小于1左移30位,2的30次方,也就是1073741824

 static final float DEFAULT_LOAD_FACTOR = 0.75f;

HashMap默认的加载因子,因为从上可知,HashMap的默认初始容量是16,当HashMap的实际容量达到16*0.75,就是12,HashMap会自动扩容。

  static final int TREEIFY_THRESHOLD = 8;

HashMap底层链表转换成红黑树的临界值,当链表的长度大于8时,会自动转化成红黑树。

static final int UNTREEIFY_THRESHOLD = 6;

HashMap底层红黑树转化成链表的临界值,当红黑树的长度小于6时,红黑树又会自动转换成链表。

static final int MIN_TREEIFY_CAPACITY = 64;

HashMap转化成树结构的最小容量,因为HashMap底层时数组+链表+红黑树实现的,HashMap的容量大于64时,会自动转换成树结构,也就是数组的长度大于64时,也会转换成红黑树。


以下是HashMap的静态内部类

static class Node<K,V> implements Map.Entry<K,V> {final int hash;//若放入的节点key的hash值(若key所在的类未进行重写hash()方法的重写,则为Object的hash()方法) 定义数组索引的位置final K key;//放入节点的keyV value;//放入节点的valueNode<K,V> next;//此节点的下一个节点Node(int hash, K key, V value, Node<K,V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}public final K getKey()        { return key; }public final V getValue()      { return value; }public final String toString() { return key + "=" + value; }public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue;}public final boolean equals(Object o) {if (o == this)return true;if (o instanceof Map.Entry) {// 判断key和value是否都相等Map.Entry<?,?> e = (Map.Entry<?,?>)o;if (Objects.equals(key, e.getKey()) &&Objects.equals(value, e.getValue()))// 如果key和value都相等,就返回truereturn true;}// 如果key或者value不相等,就返回falsereturn false;}}

继续往下看

static final int hash(Object key) { // 计算key的hash值int h;// 1.先拿到key的hashCode值; 2.将hashCode的高16位参与运算return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
static Class<?> comparableClassFor(Object x) {// 1.判断x是否实现了Comparable接口if (x instanceof Comparable) {Class<?> c; Type[] ts, as; Type t; ParameterizedType p;// 2.校验x是否为String类型if ((c = x.getClass()) == String.class) // bypass checksreturn c;if ((ts = c.getGenericInterfaces()) != null) {// 3.遍历x实现的所有接口for (int i = 0; i < ts.length; ++i) {// 4.如果x实现了Comparable接口,则返回x的Classif (((t = ts[i]) instanceof ParameterizedType) &&((p = (ParameterizedType)t).getRawType() ==Comparable.class) &&(as = p.getActualTypeArguments()) != null &&as.length == 1 && as[0] == c) // type arg is creturn c;}}}return null;
}

    /*** HashMap的成员变量数组*/transient Node<K,V>[] table;/*** 存储的是entrySet,其实里面的每个元素就是HashMap的每个节点*/transient Set<Map.Entry<K,V>> entrySet;/*** HashMap中已存元素的个数 size*/transient int size;/*** HashMap被修改的次数 put remove 操作的次数*/transient int modCount;//阈值 capacity*loadFactor 或者是将要初始化扩容的容量值int threshold;/*** 负载因子*/final float loadFactor;

简单看一下底层源码,我们可以做出以下总结:

HashMap的初始容量是16,默认加载因子是0.75,扩容按照原始容量的2倍扩容,可以存储null值和null键,因为没有加锁,当多个线程同时操作一个hashmap就可能出现不安全的情况,所以线程也是不安全的,底层是由数组+链表+红黑树实现。

当添加一个元素(key-value)时,就首先计算元素key的hash值,以此确定插入数组中的位置,但是可能存在同一hash值的元素,这时就添加到同一hash值的元素的后面,他们在数组的同一位置,但是形成了链表,同一各链表上的Hash值是相同的,所以说数组存放的是链表。而当链表长度大于8时,链表就转换为红黑树,以及当数组的长度大于64时,也会自动转换成红黑树,这样大大提高了查找的效率。

通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node(节点)添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着key和链表上每个节点的key进行equals。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals的结果返回了true,那么这个节点的value将会被覆盖。

HashMap 底层实现原理相关推荐

  1. HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理

    HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理 首先HashMap是Map的一个实现类,而Map存储形式是键值对(key,value) ...

  2. HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别(转)

    HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别 文章来源:http://www.cnblogs.com/beatIteWeNerverGiveU ...

  3. Java中HashMap底层实现原理

    Java面试绕不开的问题: Java中HashMap底层实现原理(JDK1.8)源码分析 这几天学习了HashMap的底层实现,但是发现好几个版本的,代码不一,而且看了Android包的HashMap ...

  4. java源码系列:HashMap底层存储原理详解——4、技术本质-原理过程-算法-取模具体解决什么问题

    目录 简介 取模具体解决什么问题? 通过数组特性,推导ascii码计算出来的下标值,创建数组非常占用空间 取模,可保证下标,在HashMap默认创建下标之内 简介 上一篇文章,我们讲到 哈希算法.哈希 ...

  5. HashMap底层实现原理--详细

    参考链接: Java集合 - (源码解析)"HashMap底层实现原理–详细" 为什么面试要问 hashmap 的原理

  6. 聊聊Java系列-集合之HashMap底层结构原理

    前言           由于HashMap在我们的工作和面试中会经常遇到,所以搞懂HashMap的底层结构原理就显得十分有必要了.在JDK1.8之前,HashMap的底层采用的数据结构是数组+链表, ...

  7. JDK1.7中HashMap底层实现原理

    JDK1.7中HashMap底层实现原理 一.数据结构 HashMap中的数据结构是数组+单链表的组合,以键值对(key-value)的形式存储元素的,通过put()和get()方法储存和获取对象. ...

  8. Java面试绕不开的问题: Java中HashMap底层实现原理(JDK1.8)源码分析

    这几天学习了HashMap的底层实现,但是发现好几个版本的,代码不一,而且看了Android包的HashMap和JDK中的HashMap的也不是一样,原来他们没有指定JDK版本,很多文章都是旧版本JD ...

  9. 【java】HashMap底层实现原理及面试题

    目录 一.哈希表(散列) 1.什么是哈希表 2.什么是哈希冲突(面试题) 3.解决哈希冲突的方法(面试题) (1) 开放地址法 ① 线性探查 ②二次探查 ③随机探查 (2) 再哈希法 (3) 链地址法 ...

  10. hashmap实现原理_Java中HashMap底层实现原理(JDK1.8)源码分析

    在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依 ...

最新文章

  1. 生成对抗网络学习笔记5----DCGAN(unsupervised representation learning with deep convolutional generative adv)的实现
  2. Linux系统进程管理
  3. Winform中通过代码设置DevExpress的TextEdit的类型为Numbernic
  4. 怎么发一篇IEEE文章呢?
  5. android 将SQLite数据库的表格导出为csv格式,并解析csv文件
  6. boost::log::expressions::has_attr用法的测试程序
  7. es6 数组合并_九个前端开发必学超级实用的 ES6 特性
  8. 技术大牛收割机!Java之父James Gosling现在哪里???
  9. 《Inside XAML》翻译半成品
  10. 卷积神经网络经典模型要点
  11. C#中使用post请求方法请求表单-用于两个网站的交互
  12. python获取季度函数_ORACLE时间常用函数(字段取年、月、日、季度)
  13. Linux进程实践(3) --进程终止与exec函数族
  14. 数据结构之线索化二叉树
  15. 动漫品牌“爆笑虫子”宣布与xNFT Protocol战略合作,开发NFT数字卡牌游戏
  16. keilc error C183: unmodifiable lvalue (编程时要注意啦)
  17. 怎么复制黑苹果config配置_[黑苹果硬件] 实用黑苹果配置推荐
  18. C++实现二叉树的非递归遍历
  19. python爬虫:英为财情爬取美国十年期国债收益率
  20. 《Kubernetes知识篇:Kubernetes污点和容忍度》

热门文章

  1. Windows/Mac上免费好用的压缩软件推荐(持续更新)
  2. MCSA / Windows Server 2016 用MAP工具进行IT资产评估I和虚拟化部署准备
  3. Vue之echarts圆饼图详解
  4. Java面试基础问题之(一)—— JDK和JRE区别
  5. java单例模式代码
  6. 极化码理论及算法研究5-SC算法及matlab仿真
  7. HTML页面跳转的5种方法。
  8. js mysql 住宿系统_微信小程序酒店管理信息系统研发(WebStorm,node.js,MySQL)
  9. 用matlab绘制函数图像
  10. 网站ping端口的操作方法和命令介绍