码迷,mamicode.com
首页 > 其他好文 > 详细

HashMap源码分析-基于JDK1.8

时间:2017-11-13 18:32:01      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:加载因子   ini   put   iterator   一般来说   under   因此   内容   logs   

以下内容翻译于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实例有有两个属性影响它的性能:CAPACITYLOAD_FACTORCAPACITYhash表里桶的数量,并且初始的CAPACITY仅仅是hash表创建时的容量。LOAD_FACTORhash表在自动地增加它的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

 

         

HashMap源码分析-基于JDK1.8

标签:加载因子   ini   put   iterator   一般来说   under   因此   内容   logs   

原文地址:http://www.cnblogs.com/dupang/p/7827124.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!