static final float DEFAULT_LOAD_FACTOR = 0.75f;
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}
/**
- The number of key-value mappings contained in this map.
*/
transient int size;
/**
-
阈值
-
The next size value at which to resize (capacity * load factor).
-
@serial
*/
// (The javadoc description is true upon serialization.
// Additionally, if the table array has not been allocated, this
// field holds the initial array capacity, or zero signifying
// DEFAULT_INITIAL_CAPACITY.)
int threshold;
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//实际存储方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {}
//扩容方法
final Node<K,V>[] resize() {}
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
//实际取值方法
final Node<K,V> getNode(int hash, Object key) {}
* **用法**
1. put(key,value)
调用hashCode(key),使用node存储hash,key,value,如果hashcode存在则使用链表存储。
2. get(key)
根据key的hashcode找到Entry,然后获取值对象,如果根据hashcode找到的是个链表,再去根据key.equals()判断,链表中正确的节点。
* **关于扩容**
当HashMap的大小超过了阈值(size> threshold)的时候`(默认的装填因子为0.75,也就是说当一个map填满了它定义容量的75%就会去扩容)`,HashMap大小会扩大到原来的2倍。整个过程类似于创建新的数组,将原数组的元素重新hash后放到新数组中(rehashing)。
> HashMap是非同步的,所以在多线程中使用时需要注意扩容等问题
* **相关概念**
* hashing的概念
* HashMap中解决碰撞的方法
* equals()和hashCode()的应用,以及它们在HashMap中的重要性
* 不可变对象的好处
* HashMap多线程的条件竞争
* 重新调整HashMap的大小
参考地址:[http://www.importnew.com/7099.html]( )
**_以上是网上能搜到的解释,下面是个人总结的知识点提要_**
**如面试遇到此问题,第一步,反问面试官,您说的是哪个版本的HashMap**
* hashmap底层使用 数组+链表 的数据结构,实现存储数据,使用拉链法解决碰撞问题。
* map.put(key,value)的时候,内部会对key进行一次hash算法,得到一个hash值,对这个hash值&操作得到元素在数组中的位置。
* 如果该位置没有元素,那么直接加入,如果发生碰撞了,那么用拉链法,需要遍历链表比较key和hash值,如果有就覆盖,没有就到表尾了,所以会插到表尾。
* 初始容量为16,加载因子0.75,当map添加的元素超过12个的时候会触发扩容机制。数组的容量翻倍,已经存入的元素做rehash的操作,重新在数组中找位置存储。
* java8后改为碰撞链表元素超过8个,用红黑树实现
* java8在表尾,java7是在链表头插入
**思考点:**
什么情况下考虑使用SparseArray和ArrayMap替换HashMap的情况
* * *
### 相关面试题
**1\. 为什么HashMap的容量总是2x?**
从源码中可以看到,当**putVal**方法中,是通过`tab[i = (n - 1) & hash]`得到在数组中位置的。
依稀记得当年在学校中,学到hash算法的时候,学的都是`n%size`运算,来确定数值在数组中的位置,而HashMap中为什么要用到&运算呢。
原因如下
1. 大家都知道&运算要比%运算速度快,虽然可能是几毫米的差别。
2. 在n为2x时,`(n-1)&hash == hash%n`
**为什么容量总是2x?**
首先,Hash算法要解决的一个最大的问题,就是hash冲突,既然不能避免hash冲突,那么就要有个好的算法解决。
而在做&运算时,如果选用非2n的数时,n-1转换为二进制,不能保证后几位全为1,这样做在&hash的运算中,不能做到均匀分布。违背了`(n-1)&hash`的初衷。
(16)10 = 24 = (10000)2
(16-1)10