实现接口:Serializable, Cloneable, Map<K,V>
派生自AbstractMap<K,V>
HashMap与HashTable的操作几乎相同,除了HashMap是非同步的,并且允许null的value和key。不保证map的顺序固定。
如果hash函数恰当的在桶之间分配元素,可以实现常数级性能的get和put操作。迭代器需要的时间是与hashMap的容量加上key-value映射数目成比例,因此初始化容量不要设得太高或者the load factor too low。
HashMap有两个影响性能的参数:initial capacity和load factor。capacity是hash表中桶的数目,load factor是在hash表的capacity自动增长前能填满到哪种程度的衡量参数。当哈希表中entry的数目超过load factor设定和当前capacity之积,hash表将重新哈希(内部数据结构会重构),hash表的大小会接近差不多原来的两倍。
默认的load factor=0.75。过高的load factor会降低空间开销,但是会增大大部分HashMap操作的开销。如果initial capacity比最大数目的entry/load factor还大,则rehash操作不会发生。
HashMap不是线程安全的,即多个线程同时访问哈希表,至少有一个对map结构做了修改(包括add,delete一个或多个map映射,不包括对已有key的value进行修改),必须在外部进行同步。同步的操作通常通过一些封装了map的对象来实现。也可以在创建时用Collections.synchronizedMap:
Map m = Collections.synchronizedMap(new HashMap(...));
如果map在迭代器之外做了结构性的改动,迭代器会抛出ConcurrentModificationException。
Fail-fast iterator工作在一个独立的线程中,并拥有一个mutex锁。Iterator创建后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,索引当索引指针往后移动时就找不到要迭代的对象,所以fail-fast原则的iterator会马上抛出上述异常。但当Map中只有一个元素时,这种异常不会被抛出。
initialCapacity和loadfactor的默认值分别是16和0.75。在HashMap的源码中,定义了
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
并且注释说明:Must be a power of two.
此外,最大Capacity是1<<30
inflateTable(int toSize): 初始化table,本质上新建了一个capacity大小的Entry数组;
总结:
1. HashMap是一个Entry数组,数组个数是2的x次方,数组每个单元用“桶”描述,每个桶都有一个对应的Entry链,保存了hash到该桶的数据;
2. HashMap有两个参数,容量和负载因子,分别表示桶的个数和桶个数自动增长的衡量参数,默认是16和0.75,当entry(即key-value对)的总个数超过指定阈值(容量×负载因子),则桶的个数以原来两倍大小递增,并重新进行hash计算;
3. HashMap的put和get操作都是常数级,迭代器的操作与容量和entry数目之和成比例;
4. fast-fail迭代器,当使用迭代器时,如果在迭代器外部对HashMap做了结构性的改动,则迭代器抛出concurrentModificationException;
5. HashMap是非同步的;
6. HashMap采用链地址法解决冲突;
7. HashMap的hash()计算,对每个key的hashCode还进行一次计算,目的是防止低质量的hashCode:
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
————————————————————
有关hash的详细描述可以参考http://www.iteye.com/topic/709945
通过hash之后,给定hashCode的每四位都做了不重复的^运算。尽可能的保证了hashCode每一位的变化都能参与到Entry数组的hash计算中。