关于java中的HashMap,我们在项目中经常使用到,但是我们的场景是否使用对了呢?
下面分为四个部分来阐述我的HashMap的理解
1、为什么要使用hashMap?
在项目中,需求的实现需要使用到一些数据结构来保存key-value形式的数据,也就是说hashMap其实就是一个装载数据的容器。例如,我需要查询水果的价格,那么很自然就会想到将这些数据存放在一个hashMap里面,苹果:9.88/kg,雪梨:5/kg,香蕉:5/kg,榴莲:26/kg,当我问榴莲的价格的时候,很快就知道了是26/kg。
2、hashMap的使用场景有哪些?
jdk里面是这么说的:
Hash table based implementation of the <tt>Map</tt> interface. This
* implementation provides all of the optional map operations, and permits
* <tt>null</tt> values and the <tt>null</tt> key. (The <tt>HashMap</tt>
* class is roughly equivalent to <tt>Hashtable</tt>, except that it is
* unsynchronized and permits nulls.) This class makes no guarantees as to
* the order of the map; in particular, it does not guarantee that the order
* will remain constant over time.
也就是说基于Map接口实现、允许null键/值、非同步、不保证有序(比如插入的顺序)、也不保证顺序不随时间变化。
当你需要一个效率高,不需要线性安全的map对象的时候,就可以使用hashMap
3、源码(1.7)探索
put方法:a)、检查存放的table是否为空,如果为空,则初始化,默认加载因子为0.75,table初始大小为16
b)、检查key是否为空
c)、计算key的hash值,确认key在table中的位置
d)、因为hashMap是由数组+链表实现的,需要判断table[i]中链表的元素和key是否相等,找到将老值替换为新值,然后返回。
e)、如果table[i]的元素为空,则新增一个元素,当table中的元素大小大于 capacity * loadFactor,则需要调整table的大小了,为原来的2倍,这个时候会进行数组拷贝,比较耗性能,所以如果初始化容器的时候,可以确认容器的大小,就最好直接初始化对应的table大小,不需要进行扩容
1 public V put(K key, V value) {
2 if (table == EMPTY_TABLE) {
3 inflateTable(threshold);
4 }
5 if (key == null)
6 return putForNullKey(value);
7 int hash = hash(key);
8 int i = indexFor(hash, table.length);
9 for (Entry<K,V> e = table[i]; e != null; e = e.next) {
10 Object k;
11 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
12 V oldValue = e.value;
13 e.value = value;
14 e.recordAccess(this);
15 return oldValue;
16 }
17 }
18
19 modCount++;
20 addEntry(hash, key, value, i);
21 return null;
22 }
get 方法:和put方法差不多,都是先计算hash值,然后获取table[i]链表中的数据
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
4、使用的设计模式
无
5、可能会出现的坑
在多线程环境中使用hashMap可能会出现cpu打到100%的异常,就是死循环的情况,原因是resize的时候,拷贝对象引用出现循环引用