hashMap数据结构图:
HashMap特点:
- 允许一个记录的键为null;
- 允许多条记录的值为null;
- 非线程安全,任意时刻多线程操作hashmap,有可能导致数据不一致,可以通过Collections的synchronizedMap来实现Map的线程安全或者使用concurrentHashMap。
HashMap是链表+数组结构组成,底层是数组,数组元素是单向链表。当产生hash碰撞事件,意味着一个位置插入多个元素,这个时候数组上面就会产生链表。
通过hashcode的高16位实现的,能保证数组table的length比较小的时候,保证高低bit都参与到hash计算中,不会有大的开销。
1 | processing复制代码static final int hash(Object key) { |
根据key的hash值进行value内容的查找
1 | processing复制代码 public V get(Object key) { |
1 | arcade复制代码final Node<K,V> getNode(int hash, Object key) { |
put实现:
对key的hashCode()进行hashing,并计算下标( n-1 & hash),判断该位置元素是否存在,不存在,创建Node元素,存在产生碰撞,则利用key.equals()方法去链表或树中去查找对应的节点。
1 | maxima复制代码public V put(K key, V value) { |
1 | arcade复制代码final V putVal(int hash, K key, V value, boolean onlyIfAbsent, |
resize实现:HashMap扩容实现:使用一个新的数组代替已有的容量小的数组。
1 | haxe复制代码final Node<K,V>[] resize() { |
工作原理总结:
通过hash的方法,通过put和get存储和获取对象。存储对象时,我们将K/V传给put方法时,它调用hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量(超过Load Facotr则resize为原来的2倍)。获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。如果发生碰撞的时候,Hashmap通过链表将产生碰撞冲突的元素组织起来,在Java 8中,如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。
本文转载自: 掘金