zoukankan      html  css  js  c++  java
  • HahMap相关问题

    概述

    文章对HashMap的部分细节进行介绍,JDK1.7之前有可能出现环形表的问题,而1.7之后进行了改进,文章对环形表现象的出现进行了解析,然后对HashMap注意的几个问题进行了解答。 HashMap的底层实现是数组,主要具有以下特点 :

    • 键值对都允许为空(重要)
    • 线程不安全
    • 不保证有序

    问题描述即原因

    首先看一下数据迁移的地方在哪里?JDK1.7 HashMap

    public V put(K key, V value)
    {
        ......
        //算Hash值
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        //如果该key已被插入,则替换掉旧的value (链接操作)
        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++;
        //该key不存在,需要增加一个结点
        addEntry(hash, key, value, i);
        return null;
    }
    
    
    
    //增加一节点
    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);
        //查看当前的size是否超过了我们设定的阈值threshold,如果超过,需要resize
        if (size++ >= threshold)
            resize(2 * table.length);
    }
    
    
    //重新生成空间
    void resize(int newCapacity)
    {
        Entry[] oldTable = table;
        int oldCapacity = oldTable.length;
        ......
        //创建一个新的Hash Table
        Entry[] newTable = new Entry[newCapacity];
        //将Old Hash Table上的数据迁移到New Hash Table上
        transfer(newTable);
        table = newTable;
        threshold = (int)(newCapacity * loadFactor);
    }
    
    
    //数据迁移过程
    void transfer(Entry[] newTable)
    {
        Entry[] src = table;
        int newCapacity = newTable.length;
        //下面这段代码的意思是:
        //  从OldTable里摘一个元素出来,然后放到NewTable中
        for (int j = 0; j < src.length; j++) {
            Entry<K,V> e = src[j];
            if (e != null) {
                src[j] = null;
                do {
                    Entry<K,V> next = e.next;  //NO.1
                    int i = indexFor(e.hash, newCapacity);  //NO.2
                    e.next = newTable[i]; //NO.3 把当前位置的节点放在新插进来节点的next(于是这里的当前位置在下面一步就会变成久节点了)
                    newTable[i] = e;  //NO.4 当前位置的节点放新插入的节点
                    e = next; //NO.5  e 换成链表中的下一位
                } while (e != null);
            }
        }
    
    }
    
    

    正常的情况下,下图可以看见久的往后移,新的往前插(饭堂排队吃饭插队一样)

    1297993-20191230175018110-716752968.jpg

    并发情况下,假如有两个线程执行,

    • 线程1执行到 NO.1时
    • 线程2执行完了 就会出现如下

    1297993-20191230180641217-1007710848.jpg

    问题

    图片来源与参考资料。

    哈希表如何解决Hash冲突

    1297993-20191231111704731-1516410864.png

    JDK1.7之后换成了尾插法,不会出现环形表的但是依然是线程不安全的。

    HashMap 中的 key若 Object类型, 则需实现哪些方法?

    1297993-20191231111746591-1341576390.png

    参考资料

    • https://www.jianshu.com/p/8324a34577a0
  • 相关阅读:
    table的使用
    Html标签
    mysql -4练习
    mysql -3练习(分组查询后再次筛选,顺逆序排序)
    mysql -2查询单个表的数据时添加各种条件
    mysql数据库简单练习(创建表格,增删改查数据)
    JS监视滚轮向上和向下滑动与滚轮距离上部的距离(转自网络)
    JavaScript (制造简易计算器)
    JavaScript-14(操纵属性和window)
    JavaScript-13(找到单选框的value值与复选框的全选操作)
  • 原文地址:https://www.cnblogs.com/Benjious/p/12124274.html
Copyright © 2011-2022 走看看