zoukankan      html  css  js  c++  java
  • jdk1.7 1.8 hash map 区别及一些细节

    1 扩容

    1.7

        void transfer(Entry[] newTable, boolean rehash) {
            int newCapacity = newTable.length;
            for (Entry<K,V> e : table) {
                while(null != e) {
                    Entry<K,V> next = e.next;
                    if (rehash) {
                        e.hash = null == e.key ? 0 : hash(e.key);重点
                    }
                    int i = indexFor(e.hash, newCapacity);重点
                    e.next = newTable[i];
                    newTable[i] = e;
                    e = next;
                }
            }
        }
    

    1.8

                            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;重点
                            }
    

    2 jdk8 引入红黑树

    3 1.7 先扩容再插入,1.8先插入再决定是否扩容

    4 1.7头插(

    同一位置上新元素总会被放在链表的头部位置;这样先放在一个索引上的元素终会被放到Entry链的尾部

    ),1.8尾插

    细节:为什么是8

    1)treenodes的大小大约是常规节点的两倍——决定了不能直接用,有优势也有开销

    2)红黑树平均查找长度是log(n),长度为8的时候,平均查找长度为3,如果继续使用链表,平均查找长度为8/2=4,这才有转换为树的必要

    3)还有选择6和8,中间有个差值7可以有效防止链表和树频繁转换。

    细节:为什么0.75 

    如果是0.5 , 那么每次达到容量的一半就进行扩容,默认容量是16, 达到8就扩容成32,达到16就扩容成64, 最终使用空间和未使用空间的差值会逐渐增加,空间利用率低下。  如果是1,那意味着每次空间使用完毕才扩容,在一定程度上会增加put时候的时间及hash冲突的可能,提高读写的成本

    空间使用率和性能的折中

    红黑树根据什么排序:

    如果key没有实现Comparable接口

            if (x instanceof Comparable) {
                Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
                if ((c = x.getClass()) == String.class) // bypass checks
                    return c;
                if ((ts = c.getGenericInterfaces()) != null) {
                    for (int i = 0; i < ts.length; ++i) {
                        if (((t = ts[i]) instanceof ParameterizedType) &&
                            ((p = (ParameterizedType)t).getRawType() ==
                             Comparable.class) &&
                            (as = p.getActualTypeArguments()) != null &&
                            as.length == 1 && as[0] == c) // type arg is c
                            return c;
                    }
                }
            }
            return null;
    
            static int tieBreakOrder(Object a, Object b) {
                int d;
                if (a == null || b == null ||
                    (d = a.getClass().getName().
                     compareTo(b.getClass().getName())) == 0)
                    d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
                         -1 : 1);
                return d;
            }
    

    先根据类名,再根据identityHashCode

    identityHashCode根据对象的内存地址来计算hashcode,不管对象是不是重写了hashcode

    https://blog.csdn.net/weixin_41725090/article/details/82147576

    https://blog.csdn.net/qq_36520235/article/details/82417949

  • 相关阅读:
    du熊学斐波那契I
    《博客园精华集》分类索引
    C++中指针和引用的区别
    堆和栈的区别
    getch和getchar的区别
    class和struct
    ARM开发步骤
    ARM寻址方式
    存储器映射
    思维中的错误
  • 原文地址:https://www.cnblogs.com/silyvin/p/11475086.html
Copyright © 2011-2022 走看看