以下内容翻译于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。CAPACITY是hash表里桶的数量,并且初始的CAPACITY仅仅是hash表创建时的容量。LOAD_FACTOR是hash表在自动地增加它的CAPACITY前,允许CAPACITY有多满的测量方式。当hash表里的条目的数量超过当前CAPACITY乘以LOAD_FACTOR的数量时,hash表被重新计算hash。(也就是说内部的数据结构被重建)。以便hash表具有大概两倍于原来桶数量。
一般来说,默认的loadfactory(0.75)提供了一个好的折中在时间和空间消耗上。更高的值减小了空间压力,但是增加了查询消耗(反映在HashMap中的大部分操作,包括get和put)。预计的map中的条目数量和它的loadfactory应该被考虑当设置它的初始capacity时。为了减小rehash的操作数量。如果初始capacity大于条目最大数量除以loadfactory,就不会有rehash操作发生。
如果很多映射将被存储在HashMap中。与让在需要的时候自动地执行rehash操作来扩大hash表大小相比,创建一个足够大capacity的hashMap来存储映射将是更高效的。注意,很多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