hashmap相关的问题

hashmap相关的问题

  1. hashmap源码 https://blog.csdn.net/ooo123lll/article/details/81103234#335-get
  2. hashmap扩容、为什么是2n(2的n次方)扩容 https://www.cnblogs.com/williamjie/p/9358291.html
    扩容或者初始化容量时,都是以2的n次方扩容,这主要原因是,hashmap定位key的下标的机制决定的。根据源码:
public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    // 若“key不为null”,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        // 若“该key”对应的键值对已经存在,则用新的value取代旧的value。然后退出!
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    // 若“该key”对应的键值对不存在,则将“key-value”添加到table中
    modCount++;
    addEntry(hash, key, value, i);
    return null;
}
// 返回索引值
// h & (length-1)保证返回值的小于length
static int indexFor(int h, int length) {
        return h & (length-1);
}

我们可以看到当put或者get方法时,会先对key进行hashcode获得hash值,然后用hash值和(table长度-1)进行与运算(indexFor方法),从而得到key的table数组的下标,其实除了与运算,还可以直接使用mod取余运算(hash值%(table长度-1))来获得下标位置,但由于在计算机中取余运算很耗时(计组中有学二进制的除法运算会比二进制的直接与运算复杂很多),所以hashmap采用的是运算来定位key的下标。
如果table长度是2的n次方,那么table.length-1的二进制一定是都是1,如length=16,则length-1=15 -> 1111
那么任何一个小于table.length-1的数字跟length-1进行与运算都是它本身,如9->1001,1001 & 1111 = 1001;这样能保证key的分步均匀,减少key的冲突。
但如果不是2的n次方,假设table.length=15,则table.length-1=14 -> 1110,key的hash值认为9,即1001 & 1110 = 1000 ,发现了什么?只要key的hash值的二进制位1的都不能 用了,这样会跟原本应该在***0的位置的key产生冲突,然后hashmap使用的是拉链法解决冲突,所以冲突的key会放到链表中,无冲突的hashmap取值的时间复杂度为O(1),如果冲突,则在链表中查询当前值的时间复杂度为O(n),这严重降低了hashmap的查询料率。
所以不管是在初始化容量时还是在扩容时,jdk会自动帮你选择以2den次方进行扩容。

  1. 负载因子为什么是0.75 https://www.cnblogs.com/peizhe123/p/5790252.html
    当创建 HashMap 时,有一个默认的负载因子(load factor),其默认值为 0.75,这是时间和空间成本上一种折衷:增大负载因子可以减少 Hash 表(就是那个 Entry 数组)所占用的内存空间,但会增加查询数据的时间开销,这是因为增大负载因子,那么key的冲突会增大,然后存储到链表的节点,链表的节点查询时间复杂度是O(n),而查询是最频繁的的操作(HashMap 的 get() 与 put() 方法都要用到查询);减小负载因子会提高数据查询的性能,但会增加 Hash 表所占用的内存空间,负载因子越小,table数组的位置就越来被使用。

  2. hashMap为什么线程不安全(hash碰撞与扩容导致)https://www.cnblogs.com/qiumingcheng/p/5259892.html

  3. hashmap冲突的解决方法以及原理分析:https://www.cnblogs.com/peizhe123/p/5790252.html

  4. JDK1.8对HashMap有哪些优化 hashmaphttps://blog.csdn.net/hu199055/article/details/78717544

  5. 使用类自定义hashmap的key,要重写哪些方法,hashcode方法和equals方法

发布了151 篇原创文章 · 获赞 104 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/qq_35923749/article/details/88675232