`

0001

阅读更多
hashMap  源码 简单解析。


public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
{

    /**
     * The default initial capacity - MUST be a power of two.
     *2的次方 必须是 默认初始化的大小 是16
     */
    static final int DEFAULT_INITIAL_CAPACITY = 16;

    /**
     * The maximum capacity, used if a higher value is implicitly specified
     * by either of the constructors with arguments.
     * MUST be a power of two <= 1<<30.
     *左移位   最大值  1<<30 = 1 073 741 824  2 的30次方
     *2<<3  2*2的3次方 
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * The load factor used when none specified in constructor.
     *默认负载因子 (当没有指定负载因子时 采用默认的)
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * The table, resized as necessary. Length MUST Always be a power of two.
     *数组的长度必须为2 的次幂
     */
    transient Entry[] table;

    /**
     * The number of key-value mappings contained in this map.
     */
    transient int size;

    /**
     * The next size value at which to resize (capacity * load factor).
     * 数组扩容时的长度是根据负载因子和默认长度计算出来的  eg:默认loadFactor = 0.75 ,catacity = 16 则当数组容量超过12时就进行扩容
     *容量为capacity 的2倍 即2的次幂。
     * @serial
     */
    int threshold;

    /**
     * The load factor for the hash table.
     *为数组准备的负载因子 可以自定义大小
     * @serial
     */
    final float loadFactor;

    /**
     * The number of times this HashMap has been structurally modified
     * Structural modifications are those that change the number of mappings in
     * the HashMap or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the HashMap fail-fast.  (See ConcurrentModificationException).
     *记录hashMap 被修改的次数,每次都是加一操作。
     */
    transient volatile int modCount;




//静态类 用来存放参数
    static class Entry<K,V> implements Map.Entry<K,V> {
        final K key; ----key存放键值
        V value;  ----存放键
        Entry<K,V> next; 指向下一个对象,用来当位置重复时做链表用
        final int hash; ----存放hash 值, 这里不是hashcode 是 通过hashmap的hash算法得到的hash值 但是是和hashcode有关
        如果hashcode相等,则此值也是相同的

        /**


    /**
     * Offloaded version of put for null keys
     */
    private V putForNullKey(V value) {
    /×××
    key==null时调用
   
   
   
    ××/
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {//在0索引位置开始向后循环查找查找  注意next 链表结构
        //如果这个地方有null  的key 则替换掉,否则调用下面的方法
        //注意:null的key 都是存储在0索引位置的,即table数组的第一位如果有链表则向下连
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);//这个方法是存储null 的key的
       
        return null;
    }


    /**
     * Adds a new entry with the specified key, value and hash code to
     * the specified bucket.  It is the responsibility of this
     * method to resize the table if appropriate.
     *
     * Subclass overrides this to alter the behavior of put method.
     */
    void addEntry(int hash, K key, V value, int bucketIndex) {
    //buckectIndex 是要存放value值在数组中的位置。
    //首先把backetIndex位置的数取出来,指向e
Entry<K,V> e = table[bucketIndex];

将backetIndex 位置存入新的entry 对象,此对象把原先的entry对象放到了next里
根据最近使用的数据在不远的将来还会在使用的原则,把新的entry对象放到了此处索引位置的最上面,以前的老的entry对象向下链接。
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        判断数组的长度如果超出了threshold= capacity*loadFactory  16*0.75 如果超过或者相等就会扩容数组为原来的2倍
        if (size++ >= threshold)
            resize(2 * table.length);
    }

    /**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained a mapping for the key, the old
     * value is replaced.
     *如果map里有key(通过e.hash == hash && ((k = e.key) == key || key.equals(k)) 判断的) 则用新值替换老的值,并把oldvalue返回
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     *上面的一段大体意思是 key 关联指定的value 。或者value去关联指定的key
     */
    public V put(K key, V value) {
        if (key == null)
        /××
       
        先说说key==null吧
        如果key==null  调用putFor NUllKey 方法 参数为value
       
       
       
        ×××/
            return putForNullKey(value);
           
           
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
       
        //判断此位置的链表上是否有这个key,如果有 则替换没有就调用add方法添加
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        //此处和上面是一样的,记住entry对象里存了hash值,key,value,和数组的索引位置
        addEntry(hash, key, value, i);
        return null;
    }





















































0
6
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics