jdk-map-hashMap

  关于java中的HashMap,咱们在项目中常常使用到,可是咱们的场景是否使用对了呢?java

  下面分为四个部分来阐述个人HashMap的理解设计模式

  一、为何要使用hashMap?数组

  在项目中,需求的实现须要使用到一些数据结构来保存key-value形式的数据,也就是说hashMap其实就是一个装载数据的容器。例如,我须要查询水果的价格,那么很天然就会想到将这些数据存放在一个hashMap里面,苹果:9.88/kg,雪梨:5/kg,香蕉:5/kg,榴莲:26/kg,当我问榴莲的价格的时候,很快就知道了是26/kg。安全

  二、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

  三、源码(1.7)探索ide

  put方法:a)、检查存放的table是否为空,若是为空,则初始化,默认加载因子为0.75,table初始大小为16性能

       b)、检查key是否为空ui

       c)、计算key的hash值,确认key在table中的位置this

       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;
    }

  四、使用的设计模式

   无

  五、可能会出现的坑

    在多线程环境中使用hashMap可能会出现cpu打到100%的异常,就是死循环的状况,缘由是resize的时候,拷贝对象引用出现循环引用

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息