zoukankan      html  css  js  c++  java
  • HashMap底层代码分析

    public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    //this.loadFactor为加载因子,其值为默认的加载因子常量:DEFAULT_LOAD_FACTOR的值,即0.75

    threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
    //阈值,当容量达到默认容量的75%时,自动扩容

    table = new Entry[DEFAULT_INITIAL_CAPACITY];
    //创建一个Entry数组,数组大小为默认的DEFAULT_INITIAL_CAPACITY值:16
    init();
    }


    static class Entry<K,V> implements Map.Entry<K,V> {
    //Entry是HashMap里边的一个静态内部类,内部封装了键和值

    final K key;
    V value;
    Entry<K,V> next; //next是一个Entry<K,V>对象的引用变量
    final int hash; //经过计算得出的哈希值

    /**
    * Creates new entry.
    */
    Entry(int h, K k, V v, Entry<K,V> n) {
    value = v;
    next = n;
    key = k;
    hash = h;
    }

    public final K getKey() {
    return key;
    }

    public final V getValue() {
    return value;
    }

    public final V setValue(V newValue) {
    V oldValue = value;
    value = newValue;
    return oldValue;
    }


    //存放数据:put()方法
    public V put(K key, V value) {
    if (key == null)
    return putForNullKey(value);
    //如果传进来的是个null,就返回一个null值
    int hash = hash(key.hashCode());
    /*
    先通过键的hashCode()方法获得一个整型值,然后通过hash(int h)这个散列函数得到一个散列码
    static int hash(int h) {
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
    }


    */
    int i = indexFor(hash, table.length);
    //把散列值和数组的长度来进行运算,最终得到Entry对象要存放到数组的位置(下标)

    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++;
    addEntry(hash, key, value, i); //直接存放
    return null;
    }

    *
    * hashmap调用默认构造方法会产生一个默认底层是长度为16的Entry数组,首先调用key的hasCode()方法来得到一个整数,
    * int hash = hash(key.hashCode());
    * 这个整数就是哈希码,然后把哈希码作为参数传递到hash()函数中来进行运算,即散列运算,得到一个int类型的散列值
    * int i = indexFor(hash, table.length);
    * 把散列值和数组的长度来进行运算,最终得到Entry对象要存放到数组的位置(下标)
    *
    * hashmap内部的结构是数组加单向链表结构,因为不同的key有可能计算出相同的散列值,根据散列值计算出来的存放到数组的下标
    * 会冲突(同一个下标值),此时, 如果键相同,散列值也一样,说明是同一个对象,此时会将键所对应的旧值用新的键值覆盖掉
    * 如果散列值一样,键名不一样,说明是不同的对象,此时会把键值对封装成entry对象放到那个散列值对应的下标位置处,
    * 原来那个entry对象会以链表形式链接在新创建的entry对象后面
    */





    void addEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
    if (size++ >= threshold)
    resize(2 * table.length);
    }

  • 相关阅读:
    国外程序员整理的 C++ 资源大全
    31部黑客电影
    向windows添加环境变量
    windows 查看动态连接库和静态连接库的方法
    十大最值得注意的MySQL变量
    源码圈 300 胖友的书单整理
    82岁“极客”老人用云计算写族谱, 90后败给“30”后!
    Redis 实现队列http://igeekbar.com/igeekbar/post/436.htm
    借助CSS Shapes实现元素滚动自动环绕iPhone X的刘海
    听说程序猿的密码大多是这样滴~看完心累中。。。
  • 原文地址:https://www.cnblogs.com/enjoyjava/p/6876342.html
Copyright © 2011-2022 走看看