zoukankan      html  css  js  c++  java
  • jdk1.8中hashmap

    1.在jdk1.8以前,hashmap的实现原理是数组+链表,在1.8以后实现就变成了数组+链表+红黑树。这样实现的好处是防止某个链表中的元素数量过多,导致hashmap的整体性能下降,所以在1.8以后改为当链表中的元数量大于8时,就把链表改成红黑树,以提高效率。在红黑树中元素的数量小于6时,就会变成链表。

    2.关于hashmap的put()的具体实现如下:

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,

    boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
    n = (tab = resize()).length; //如果数组没有就初始化数组
    if ((p = tab[i = (n - 1) & hash]) == null)
    tab[i] = newNode(hash, key, value, null); //如果数组中 该位置没有元素 就直接插入
    else {
    Node<K,V> e; K k;
    if (p.hash == hash &&
    ((k = p.key) == key || (key != null && key.equals(k))))
    e = p; //数组中存在key
    else if (p instanceof TreeNode)
    e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); // 如果数组中存在该元素 并且元素类型为树节点 则进行红黑树的插入
    else {
    for (int binCount = 0; ; ++binCount) { //循环遍历该链表
    if ((e = p.next) == null) {
    p.next = newNode(hash, key, value, null);
    if (binCount >= TREEIFY_THRESHOLD - 1) //若不存在key 则插入该链表的最后,如果链表长度超过阈值 则树化
    treeifyBin(tab, hash);
    break;
    }
    if (e.hash == hash &&
    ((k = e.key) == key || (key != null && key.equals(k)))) //若该链表中存在该key 跳出循环
    break;
    p = e;
    }
    }
    if (e != null) { //如果该hashmap中存在该key 则返回原先的值
    V oldValue = e.value;
    if (!onlyIfAbsent || oldValue == null)
    e.value = value;
    afterNodeAccess(e);
    return oldValue;
    }
    }
    ++modCount;
    if (++size > threshold) //判断容量是否已经超过阈值,若超过 则进行扩容
    resize();
    afterNodeInsertion(evict);
    return null;
    }

    3.关于hashmap 的get()的具体实现如下:

    final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
    (first = tab[(n - 1) & hash]) != null) { //判断数组不为空 为空则返回null
    if (first.hash == hash && // always check first node
    ((k = first.key) == key || (key != null && key.equals(k)))) //如果第一个节点是 则返回第一个节点
    return first;
    if ((e = first.next) != null) { //遍历
    if (first instanceof TreeNode)
    return ((TreeNode<K,V>)first).getTreeNode(hash, key); //如果是树节点 则调用红黑树的取值
    do { //循环遍历链表
    if (e.hash == hash &&
    ((k = e.key) == key || (key != null && key.equals(k))))
    return e;
    } while ((e = e.next) != null);
    }
    }
    return null;
    }

    3.关于hashmap的resize()方法具体实现如下:

    final Node<K,V>[] resize() {
    Node<K,V>[] oldTab = table;
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    int oldThr = threshold;
    int newCap, newThr = 0;
    if (oldCap > 0) {
    if (oldCap >= MAXIMUM_CAPACITY) { //如果原先的容器容量已经大于等于规定的最大值(2的30次方)了,则扩容后的新的容量是2的31次方-1
    threshold = Integer.MAX_VALUE;
    return oldTab;
    }
    else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
    oldCap >= DEFAULT_INITIAL_CAPACITY)
    newThr = oldThr << 1; // 两倍扩容
    }
    else if (oldThr > 0) // initial capacity was placed in threshold
    newCap = oldThr;
    else { // zero initial threshold signifies using defaults 初始化的容量
    newCap = DEFAULT_INITIAL_CAPACITY;
    newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    if (newThr == 0) {
    float ft = (float)newCap * loadFactor;
    newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
    (int)ft : Integer.MAX_VALUE);
    }
    threshold = newThr;
    @SuppressWarnings({"rawtypes","unchecked"})
    Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; //创建一个新的容器 需要把原先所有的数据重新散列到新的容器中
    table = newTab;
    if (oldTab != null) {
    for (int j = 0; j < oldCap; ++j) {
    Node<K,V> e;
    if ((e = oldTab[j]) != null) {
    oldTab[j] = null; //原先数组中该元素复制为空 便于资源回收
    if (e.next == null) //如果没有链表 直接插入到新的容器中
    newTab[e.hash & (newCap - 1)] = e;
    else if (e instanceof TreeNode) //如果是树节点 则调用红黑树的分离插入
    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
    else { // preserve order
    Node<K,V> loHead = null, loTail = null;
    Node<K,V> hiHead = null, hiTail = null;
    Node<K,V> next;
    do {
    next = e.next;
    if ((e.hash & oldCap) == 0) {
    if (loTail == null)
    loHead = e;
    else
    loTail.next = e;
    loTail = e;
    }
    else {
    if (hiTail == null)
    hiHead = e;
    else
    hiTail.next = e;
    hiTail = e;
    }
    } while ((e = next) != null); //把一个链表分离成两个并插入到新的链表中
    if (loTail != null) {
    loTail.next = null;
    newTab[j] = loHead;
    }
    if (hiTail != null) {
    hiTail.next = null;
    newTab[j + oldCap] = hiHead;
    }
    }
    }
    }
    }
    return newTab;
    }

  • 相关阅读:
    免费的视频、音频转文本
    Errors are values
    Codebase Refactoring (with help from Go)
    Golang中的坑二
    Cleaner, more elegant, and wrong(msdn blog)
    Cleaner, more elegant, and wrong(翻译)
    Cleaner, more elegant, and harder to recognize(翻译)
    vue控制父子组件渲染顺序
    computed 和 watch 组合使用,监听数据全局数据状态
    webstorm破解方法
  • 原文地址:https://www.cnblogs.com/yelele/p/10835720.html
Copyright © 2011-2022 走看看