HashMap源码分析-基于JDK1.8

以下内容翻译于HashMap类的注释

HashMap是map接口的基础实现类。这个实现提供了所有可选的Map接口操作。并且允许null键和null值。HashMap类和Hashtable类差不多,只是HashMap不是线程完全的,并且HashMap允许null值和null键。这个类不保证map元素的顺序,也不保证顺序会随着时间保持不变。

假如hash函数能够使元素在桶中(buckets)均匀地分散,HashMap对于基本的get,put操作提供稳定的性能。集合视图的遍历需要的时间和HashMap的"capacity"(buckets的数据)乘以数量(bucket中的健值对的数量)成正比。因此如果遍历性能非常重要,那么就不要把初始的CAPACITY设置太大(或者LOAD_FACTOR太小)。

HashMap实例有有两个属性影响它的性能:CAPACITY和LOAD_FACTOR。CAPACITYhash表里桶的数量,并且初始的CAPACITY仅仅是hash表创建时的容量。LOAD_FACTOR是hash表在自动地增加它的CAPACITY前,允许CAPACITY有多满的测量方式。当hash表里的条目的数量超过当前CAPACITY乘以LOAD_FACTOR的数量时,hash表被重新计算hash。(也就是说内部的数据结构被重建)。以便hash表具有大概两倍于原来桶数量。

一般来说,默认的loadfactory(0.75)提供了一个好的折中在时间和空间消耗上。更高的值减小了空间压力,但是增加了查询消耗(反映在HashMap中的大部分操作,包括getput)。预计的map中的条目数量和它的loadfactory应该被考虑当设置它的初始capacity时。为了减小rehash的操作数量。如果初始capacity大于条目最大数量除以loadfactory,就不会有rehash操作发生。

如果很多映射将被存储在HashMap中。与让在需要的时候自动地执行rehash操作来扩大hash表大小相比,创建一个足够大capacityhashMap来存储映射将是更高效的。注意,很多key具有相同的hashCode()值是一个肯定的方法来降低任何hash表的性能的方式。

注意这个实现不是synchronized的().如果多个线程同时访问hashMap,并且只要有一个线程修改map结构,它就必须在外面被加上synchronized。(结构的修改是指任何增加或删除一个或多个的映射,仅仅修改一个健的值不是结构的修改)。这通常通过在天然地包裹map的对象上同步来实现。如果没有这样的对象存在。map应该用Collections.synchronizedMap方法包装一下。为了防止对map意外的不同步的访问,最好在创建的时候完成这样的操作。例如

Map m = Collections.synchronizedMap(new HashMap(...))

被这个类的”集合视图方法”返回的所有遍历器都是快速失败的:在这个遍历器创建之后,用任何方法除了iterator自身的remove方法修改map的结构将会抛出ConcurrentModificationException。因此面对同时的修改,遍历器快速而干净利落地失败。而不是在不确定的未来冒着不确定的危险。

注意,遍历器快速失败的行为不能被用来保证它看起来的样子。换句话说,在不同步的同时修改前面不能做任何强的担保。快速失败的遍历器尽量地抛出ConcurrentModificationException。写的程序依赖这个异常来保证正确性将是错误的。iterators的快速失败行为应该只被用于检测错误。

HashMap的几个重要的字段

/** * 默认的CAPACITY值,也就是16,这个值必须是2的幂 */
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
 * capacity最大值, 当在构造器中传入一个比这大的参数的时候使用。
 * 也就是说,当传入的值大于这个值,就使用这个值
 * 必须是2的幂
 */
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
 * 在构造器中没有指定的时候被使用的默认的加载因子.
 */
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
  * 使用树而不是列表的bin中的数量阀值,当在bin中增加数据的时候,大于这个值 * 就会把bin中的数据从列表转换成红黑树结构来表示。这个值必须大于2并且应该小 * 小于8。 
  */static final int TREEIFY_THRESHOLD = 8;
/**
 * 在resize操作中把bin中数据变为列表结构的数量阀值,如果小于这个值,就会
 * 从树结构变为列表结构。这个值应该小于TREEIFY_THRESHOLD并且最大为6。
 * most 6 to mesh with shrinkage detection under removal.
 */
static final int UNTREEIFY_THRESHOLD = 6;
/**
 * 当bin中的结构转换为树的时候,CAPACITY的最小值.
 * 否则就会resize当bin中数据太多的时候。应该至少4 * TREEIFY_THRESHOLD
 * 来避免resizing和树转换阀值之间的冲突。
 * between resizing and treeification thresholds.
 */
static final int MIN_TREEIFY_CAPACITY = 64;

内部类

 1 /**
 2      * Basic hash bin node, used for most entries.  (See below for
 3      * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
 4      */
 5     static class Node<K,V> implements Map.Entry<K,V> {
 6         final int hash;
 7         final K key;
 8         V value;
 9         Node<K,V> next;
10
11         Node(int hash, K key, V value, Node<K,V> next) {
12             this.hash = hash;
13             this.key = key;
14             this.value = value;
15             this.next = next;
16         }
17
18         public final K getKey()        { return key; }
19         public final V getValue()      { return value; }
20         public final String toString() { return key + "=" + value; }
21
22         public final int hashCode() {
23             return Objects.hashCode(key) ^ Objects.hashCode(value);
24         }
25
26         public final V setValue(V newValue) {
27             V oldValue = value;
28             value = newValue;
29             return oldValue;
30         }
31
32         public final boolean equals(Object o) {
33             if (o == this)
34                 return true;
35             if (o instanceof Map.Entry) {
36                 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
37                 if (Objects.equals(key, e.getKey()) &&
38                     Objects.equals(value, e.getValue()))
39                     return true;
40             }
41             return false;
42         }
43     }

Node

        

时间: 2024-10-02 13:14:02

HashMap源码分析-基于JDK1.8的相关文章

HashMap源码分析(JDK1.8)- 你该知道的都在这里了

我的csdn博客地址: http://blog.csdn.net/brycegao321 HashMap是Java和Android程序员的基本功, JDK1.8对HashMap进行了优化, 你真正理解它了吗? 考虑如下问题: 1.哈希基本原理?(答:散列表.hash碰撞.链表.红黑树) 2.hashmap查询的时间复杂度, 影响因素和原理? (答:最好O(1),最差O(n), 如果是红黑O(logN)) 3.resize如何实现的, 记住已经没有rehash了!!!(答:拉链entry根据高位b

HashMap 源码分析 基于1.8

1.个人总结及想法: (1)1.8相比较于1.7的变化? HashMap的底层数据结构大家应该都比较清楚了,就是数组+链表,链表主要用来解决hash冲突,使用了链地址法的方式来解决,1.8的改动主要就是hash冲突时候,一是在进行链表插入时由1.7的头插法变成了尾插法,第二个原来链表是一个单链表,但是现在超过红黑树的阀值过后就会自动升级为红黑树,阀值是链表节点超过8个节点(建立在数组已经扩容到64,否则优先选择扩容来解决冲突).当链表节点少于6个时红黑树会退化成普通链表. (2)1.8会出现1.

HashMap源码分析(JDK1.8)

一.HashMap简介 HashMap是一种基于数组+链表+红黑树的数据结构,其中红黑树部分在JDK1.8后引入,当链表长度大于8的时候转换为红黑树. HashMap继承于AbstractMap(Map的骨架实现类),实现Map接口. HashMap因为采用hashCode的值存储,所以性能一般情况下为O(1).   HashMap最多只允许一条记录的键为null,允许多条记录的值为null. HashMap线程不安全,如在多线程环境下可以使用Collections工具类将其转换为线程安全,也可

ArrayList源码分析(基于JDK1.8)

ArrayList底层是一个Object类型数组 .对数组的所有增删改查操作都是基于数组的. ArrayList的属性 //默认初始化容量是10 private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; //ArrayList默认初始化大小 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEM

ArrayList的源码分析(基于jdk1.8)

1.初始化 transient Object[] elementData; //实际存储元素的数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; public ArrayList() { //初始化为一个默认的空数组 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } 2. 添加元素 private static final int DEFAU

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时,链表结构

【JAVA集合】HashMap源码分析(转载)

原文出处:http://www.cnblogs.com/chenpi/p/5280304.html 以下内容基于jdk1.7.0_79源码: 什么是HashMap 基于哈希表的一个Map接口实现,存储的对象是一个键值对对象(Entry<K,V>): HashMap补充说明 基于数组和链表实现,内部维护着一个数组table,该数组保存着每个链表的表头结点:查找时,先通过hash函数计算hash值,再根据hash值计算数组索引,然后根据索引找到链表表头结点,然后遍历查找该链表: HashMap数据

Java集合系列之HashMap源码分析

一.HashMap简介 HashMap是基于哈希表的Map接口实现的,它存储的是内容是键值对<key,value>映射.此类不保证映射的顺序,假定哈希函数将元素适当的分布在各桶之间,可为基本操作(get和put)提供稳定的性能. ps:本文中的源码来自jdk1.8.0_45/src. 1.重要参数 HashMap的实例有两个参数影响其性能. 初始容量:哈希表中桶的数量 加载因子:哈希表在其容量自动增加之前可以达到多满的一种尺度 当哈希表中条目数超出了当前容量*加载因子(其实就是HashMap的

Java集合之HashMap源码分析

一.HashMap简介 HashMap是基于哈希表的Map接口实现的,它存储的是内容是键值对<key,value>映射.此类不保证映射的顺序,假定哈希函数将元素适当的分布在各桶之间,可为基本操作(get和put)提供稳定的性能. ps:本文中的源码来自jdk1.8.0_45/src. 1.重要参数 HashMap的实例有两个参数影响其性能. 初始容量:哈希表中桶的数量 加载因子:哈希表在其容量自动增加之前可以达到多满的一种尺度 当哈希表中条目数超出了当前容量*加载因子(其实就是HashMap的