HashMap原理

简介

  • 是一个散列表,它存储的内容是键值对(key-value)映射
  • 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口
  • 不是同步的(不是线程安全的)
  • key、value都可以为null(当HashMap的key为null时,HashMap会将其固定的插入table[0]位置(即HashMap散列表的第一个位置);而且table[0]处只会容纳一个key为null的值,当有多个key为null的值插入的时候,table[0]会保留最后插入的value。)
  • 映射不是有序的
  • 数据结构由数组+单向链表组成,数组决定桶的数量
  • 初始容量 :容量是哈希表中桶的数量,默认为16
  • 加载因子:是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。默认加载因子是 0.75,过低则数据分布稀疏浪费空间且频繁rehash,过高则数据分布稠密增加查询成本
  • 增加键值对时将key和链表中的每一个节点的key进行对比。若key已经存在Entry链表中,则用该value值取代旧的value值;若key不存在Entry链表中,则新建一个key-value节点,并将该节点插入Entry链表的表头位置
  • hash算法采用自定义的哈希算法

构造函数

1
2
3
4
5
6
7
8
9
10
11
// 默认构造函数。
HashMap()

// 指定“容量大小”的构造函数
HashMap(int capacity)

// 指定“容量大小”和“加载因子”的构造函数
HashMap(int capacity, float loadFactor)

// 包含“子Map”的构造函数
HashMap(Map<? extends K, ? extends V> map)

数据结构

  • table是一个Entry[]数组类型,而Entry实际上就是一个单向链表(拉链法解决哈希冲突)。哈希表的”key-value键值对”都是存储在Entry数组中的
  • size是HashMap的大小,它是HashMap保存的键值对的数量
  • threshold是HashMap的阈值,用于判断是否需要调整HashMap的容量。threshold的值=”容量*加载因子”,当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍。
  • loadFactor就是加载因子
  • modCount是用来实现fail-fast机制的,原理是当多线程操作时会修改modCount,如果发现有变动则触发fail-fast机制

JDK1.7与1.8的区别

JDK7之前hashmap又叫散列链表:基于一个数组以及多个链表的实现,hash值冲突的时候,就将对应节点以链表的形式存储。JDK8中,当同一个hash值(Table上元素)的链表节点数不小于8时,将不再以单链表的形式存储了,会被调整成一颗红黑树。这就是JDK7与JDK8中HashMap实现的最大区别。


遍历方法

当我们通过entrySet()获取到的Iterator的next()方法去遍历HashMap时,实际上调用的是 nextEntry() 。而nextEntry()的实现方式,先遍历Entry(根据Entry在table中的序号,从小到大的遍历);然后对每个Entry(即每个单向链表),逐个遍历。




版权声明:本文为博主原创文章,欢迎转载,转载请注明作者、原文超链接,感谢各位看官!!!

本文出自:monkeyGeek

座右铭:生于忧患,死于安乐

欢迎志同道合的朋友一起交流、探讨!

monkeyGeek

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×