HashMap源码解读(jdk1.8)

  一般在工作中,只有出问题的时候才会看看源码,很少有时间去单独看一下源码。

正好还没找到工作,朋友提了一句看看HashMap,所以花了点时间看了看。

对于翻源码这件事情,如果没有使用过,自己会像无头苍蝇一样,不知道从哪里开始。

对于HashMap,常用作key value容器,基本的使用方式,就是new 一个实例,put、get,或者通过keyset、entry遍历。

Map map = new HashMap();

map.put(XX,XX);  map.get(XX,XX);

  map.keySet(); map.entrySet();

按照这个思路,我开始看源码了:

1.看构造函数

可入参的变量只有两个,中文翻译过来,一个是容量cap,一个是因子factor。

默认cap=16,factor=0.75。其实还有一个极限值,默认情况下是16*0.75=12,在resize()里面。

2.存储结构

        最外层是数组Node<K,V>[] table;

在put或get的时候,都会取key的hash值无符号右移做做异或预算,形成新的hash值,并用hash值作为数据下标,存入或者定位Node。

table数组中存放的不止是Node对象,还有TreeNode对象,TreeNode继承自LinkedMap.Entry<K,V>,LinkedMap.Entry<K,V>继承自Node。

其中,使用Node或者TreeNode是有要求的,类中有TREEIFY_THRESHOLD和UNTREEIFY_THRESHOLD作为转化的数量参考。

Node本身是链表结构,当相同hash值的key被存入,会对比hash值大小,来决定Node.next的值。

TreeNode中,则是主要维护TreeNode.left和TreeNode.right.

就是说,虽然是数组,但数组中的每一个Node,不一定只存了一个key和value。

按照HashMap中hash方法的说明,已经尽量减少冲突了。

基本结构如图

3.容量变化

              根据resize()方法,当size>极限值,就是第一条中说的,默认是16*0.75的,容量和极限值都会左移1位,即乘2。

当Node里面的数量>=TREEIFY_THRESHOLD-1的时候,该Node需要转化为TreeNode

4.额外说明

               在HashMap中,设置初始容量之后,初始容量不一定等于你设置的数量。

只是16恰巧满足条件,计算初始容量的代码如下

这个方法,我的结论是为了保证容量2的n次方。

减一是因为2进制从0开始,又因为int转2进制,打印出来一共32位,所以分别右移2、4、8、16,将设定的数值的2进制lowbit都变成1,这样最后加1后,得到的数字肯定是2的n次方。

我的猜测是,因为使用了TreeNode,所以极限情况下,就是数组中全是TreeNode,达到极限的数量时,能满足二叉树结构的数量。

原文地址:https://www.cnblogs.com/xuezhankui/p/10461810.html

时间: 2024-10-11 17:30:38

HashMap源码解读(jdk1.8)的相关文章

HashMap源码分析--jdk1.8

JDK1.8 ArrayList源码分析--jdk1.8LinkedList源码分析--jdk1.8HashMap源码分析--jdk1.8 HashMap概述 ??1. HashMap是可以动态扩容的数组,基于数组.链表.红黑树实现的集合.??2. HashMap支持键值对取值.克隆.序列化,元素无序,key不可重复value可重复,都可为null.??3. HashMap初始默认长度16,超出扩容2倍,填充因子0.75f.??4.HashMap当链表的长度大于8的且数组大小大于64时,链表结构

HashMap源码分析 (JDK1.7)

看HashMap源码有一段时间了,但是一直没有写点什么,这几天趁着要换实习公司,没什么事做,就把自己对HashMap的理解写下来,边写边整理自己的思路. 这是借用别人画的理解HashMap的图,简单理解就是它结合了数组查找快和链表插入删除快的优势. 下面直接分析源码: 先从构造函数说起: public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumen

深入理解JAVA集合系列:HashMap源码解读

初认HashMap 基于哈希表(即散列表)的Map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键. HashMap继承于AbstractMap,实现了Map.Cloneable.java.io.Serializable接口.且是不同步的,意味着它不是线程安全的. HashMap的数据结构 在java编程语言中,最基本的结构就两种,一个是数组,另一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的.HashMap也不例外,它是一个“链表的数组”的数据结构

HashMap 源码解读

这几天看了一下HashMap的源码,现此于大家分享! 1,HashMap的底层实现. 2,HashMap的扩容机制. 1,底层实现 public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); } 此为Ha

hashMap 源码解读理解实现原理和hash冲突

hashMap 怎么说呢. 我的理解是 外表是一个set 数组,无序不重复 . 每个set元素是一个bean ,存着一对key value 看看代码吧 package test; import java.util.HashMap; import java.util.Map.Entry; public class HashMaptest { public static void main(String[] args) { HashMap<String, String> map = new Has

HashMap源码解读

底层实质就是一个数组,数组里面装的是Entry类的对象,next指针指向下一个节点 package a.b.c.d.e.f; import java.io.*; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.ConcurrentModificationExce

HashMap源码分析jdk1.6

 1.定义 public interface Map<K,V> { int size(); boolean isEmpty(); boolean containsKey(Object key); boolean containsValue(Object value); V get(Object key); V put(K key, V value); V remove(Object key); void putAll(Map<? extends K, ? extends V> m)

HashMap源码分析二

jdk1.2中HashMap的源码和jdk1.3中HashMap的源码基本上没变.在上篇中,我纠结的那个11和101的问题,在这边中找到答案了. jdk1.2 public HashMap() { this(101, 0.75f); } public HashMap(Map t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); } jdk1.3 public HashMap() { this(11, 0.75f); } public Has

AQS源码分析--jdk1.8

JDK1.8 ArrayList源码分析--jdk1.8LinkedList源码分析--jdk1.8HashMap源码分析--jdk1.8AQS源码分析--jdk1.8 AbstractQueuedSynchronizer概述 ??1. AQS是一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.??2. AQS提供了双向链表.??3. AQS分为共享模式和独占模式.??4.AQS基于volatile内存可见性和CAS原子性操作实现线程间通信操作. AbstractQueuedS