关于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的时候,拷贝对象引用出现循环引用