• HashMap实现原理,源码分析


    一、源码分析 

    全文可参考知乎上美团官方写的:https://zhuanlan.zhihu.com/p/21673805

    定义数组的初始容量。

    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    定义数组最大容量

    static final int MAXIMUM_CAPACITY = 1 << 30;

    定义负载因子默认值

    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    定义阈值默认值

    static final int TREEIFY_THRESHOLD = 8;
     static class Node<K,V> implements Map.Entry<K,V> {
            final int hash;
            final K key;
            V value;
            Node<K,V> next;
    
            Node(int hash, K key, V value, Node<K,V> next) {
                this.hash = hash;
                this.key = key;
                this.value = value;
                this.next = next;
            }
    
            public final K getKey()        { return key; }
            public final V getValue()      { return value; }
            public final String toString() { return key + "=" + value; }
    
            public final int hashCode() {
                return Objects.hashCode(key) ^ Objects.hashCode(value);//重写hashCode函数,为键值的hashCode值异或
            }
    
            public final V setValue(V newValue) {
                V oldValue = value;
                value = newValue;
                return oldValue;
            }
    
            public final boolean equals(Object o) {
                if (o == this)
                    return true;
                if (o instanceof Map.Entry) {
                    Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                    if (Objects.equals(key, e.getKey()) &&
                        Objects.equals(value, e.getValue()))
                        return true;
                }
                return false;
            }
        }
    static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }

    HashMap#hash(),即上面的函数。

    参考:https://blog.csdn.net/fan2012huan/article/details/51097331

     static final int tableSizeFor(int cap) {
            int n = cap - 1;
            n |= n >>> 1;
            n |= n >>> 2;
            n |= n >>> 4;
            n |= n >>> 8;
            n |= n >>> 16;
            return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
        }

    HashMap#tableSizeFor() :获取大于这个方法用于找到大于等于initialCapacity的最小的2的幂

    参考:https://blog.csdn.net/fan2012huan/article/details/51097331

     static Class<?> comparableClassFor(Object x) {
            if (x instanceof Comparable) {
                Class<?> c; Type[] ts, as; ParameterizedType p;
                if ((c = x.getClass()) == String.class) // bypass checks
                    return c;
                if ((ts = c.getGenericInterfaces()) != null) {
                    for (Type t : ts) {
                        if ((t 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;
        }

    comparableClassFor:HashMap类中有一个comparableClassFor(Object x)方法,当x的类型为X,且X直接实现了Comparable接口(比较类型必须为X类本身)时,返回x的运行时类型;否则返回null。

    instanceof

    x instanceof Comparable

    instanceof 可以理解为某种类型的实例,无论是运行时类型,还是它的父类,它实现的接口,它的父类实现的接口,甚至它的父类的父类的父类实现的接口的父类的父类,总之,只要在继承链上有这个类型就可以了。

    getClass()

    c = x.getClass()

    与instanceof相应对的是getClass()方法,无论该对象如何转型,getClass()返回的只会是它的运行时类型,可以简单的理解为它的实际类型,也就是new它的时候的类型。 
    有一种例外情况,匿名对象。当匿名对象调用getClass()时返回的是依赖它的对象的运行时类型,并以1,2,3…的索引区分。

    public class Demo {
        public static void main(String[] args) {
            D d = new D();
            System.out.println(new A(){}.getClass());   // class Demo$1
            System.out.println(new B(){}.getClass());   // class Demo$2
            System.out.println(new Comparable<Object>(){    // class Demo$3
                @Override
                public int compareTo(Object o) {
                    return 0;
                }}.getClass());
            System.out.println(d.c.getClass()); // class D$1
        }
    }
     
    abstract class A{}
    abstract class B{}
    abstract class C{}
    class D{
        C c;
        D(){
            c= new C(){};
        }
    }

    参考:https://blog.csdn.net/qpzkobe/article/details/79533237

    resize:初始化table数组或者扩容

     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) {
                    threshold = Integer.MAX_VALUE;
                    return oldTab;
                }
                else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                         oldCap >= DEFAULT_INITIAL_CAPACITY)
                    newThr = oldThr << 1; // double threshold
            }
            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;
        }

    参考:https://blog.csdn.net/u013494765/article/details/77837338

  • 相关阅读:
    Query实例的ajax应用之二级联动的后台是采用php来做的
    关于jquery的css的一些知识
    这个代码给所有带有name属性的链接加了一个背景色
    jQuery生成一个DIV容器,ID是"rating".
    被included或者被required的文件都来自哪里呢
    msql_createdb: 建立一个新的 mSQL 数据库。
    php中调用这个功能可以在web页面中显示hello world这个经典单词
    啦啦啦测试心得
    maven命令
    robotframework使用
  • 原文地址:https://www.cnblogs.com/UalBlog/p/10796724.html
Copyright © 2020-2023  润新知