zoukankan      html  css  js  c++  java
  • HashMap 1.8 源码

    public class HashSet<E> {//1.8版本
        private transient HashMap<E,Object> map;
        //1-1. 创建一个HashMap对象,并且调用无参构造函数
        public HashSet() {
            map = new HashMap<>();
        }
        
        public HashSet(int initialCapacity, float loadFactor) {
            map = new HashMap<>(initialCapacity, loadFactor);
        }
    
        public HashSet(int initialCapacity) {
            map = new HashMap<>(initialCapacity);
        }
        
        //2-1. 添加第一个元素,调用add方法
        public boolean add(E e) {
            return map.put(e, PRESENT)==null;
        }
        
        //-----------HashMap源码---------------------------
        
        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;
        
        transient Node<K,V>[] table;
        
        //1-2. 负载因子赋值为默认值0.75
        public HashMap() {
            this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
        }
        
        public HashMap(int initialCapacity) {
            this(initialCapacity, DEFAULT_LOAD_FACTOR);
        }
        
        public HashMap(int initialCapacity, float loadFactor) {
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal initial capacity: " +
                                                   initialCapacity);
            if (initialCapacity > MAXIMUM_CAPACITY)
                initialCapacity = MAXIMUM_CAPACITY;
            if (loadFactor <= 0 || Float.isNaN(loadFactor))
                throw new IllegalArgumentException("Illegal load factor: " +
                                                   loadFactor);
            this.loadFactor = loadFactor;
            this.threshold = tableSizeFor(initialCapacity);
        }
        
        //2-2. 进入HashMap的put方法中
        public V put(K key, V value) {
            //2-3. key = Student{id=1, name='lili'} value=PRESENT,对key进行hash运算
            //2-5. 走putVal方法
            return putVal(hash(key), key, value, false, true);
        }
        
        //2-4. 扰动函数,避免hash碰撞,每个版本的算法不一样。
        static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }
        
        
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                       boolean evict) {
            Node<K,V>[] tab; Node<K,V> p; int n, i;
            //2-5. 此时数组为空,所以进if
            if ((tab = table) == null || (n = tab.length) == 0)
                //2-6. 走resize方法,resize方法返回一个长度为16的Node[]
                //2-14. n = 16
                n = (tab = resize()).length;
                //2-15. (n - 1) & hash 根据这个表达式算出元素在数组的下标位置
                //2-16.  (p = tab[i = (n - 1) & hash]) == null 判断数组中该位置是否已经有数据了
            if ((p = tab[i = (n - 1) & hash]) == null)
                //2-17. 创建一个Node,然后放到数组对应下标的位置上
                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;
                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) // -1 for 1st
                                treeifyBin(tab, hash);
                            break;
                        }
                        if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                            break;
                        p = e;
                    }
                }
                if (e != null) { // existing mapping for key
                    V oldValue = e.value;
                    if (!onlyIfAbsent || oldValue == null)
                        e.value = value;
                    afterNodeAccess(e);
                    return oldValue;
                }
            }
            ++modCount;
            //4-1.如果超过扩容边界值12,就扩容
            if (++size > threshold)
                resize();
            afterNodeInsertion(evict);//啥也没干
            return null;
        }
        
        final Node<K,V>[] resize() {
            //2-7 oldTab = null;
            //4-2. oldTab = new Node[16];
            Node<K,V>[] oldTab = table;
            //4-3 oldCap = 16
            int oldCap = (oldTab == null) ? 0 : oldTab.length;//oldCap = 0
            //4-4 oldThr = 12
            int oldThr = threshold;// oldThr = 0;
            int newCap, newThr = 0;
            if (oldCap > 0) {
                if (oldCap >= MAXIMUM_CAPACITY) {
                    threshold = Integer.MAX_VALUE;
                    return oldTab;
                }
                //4-5. (newCap = oldCap << 1 newCap = oldCap*2=32 数组长度扩展为原来的2倍
                else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                         oldCap >= DEFAULT_INITIAL_CAPACITY)
                    newThr = oldThr << 1; // newThr=24,扩容临界也扩为原来的2倍
            }
            else if (oldThr > 0) 
                newCap = oldThr;
            else {
                //2-8. newCap = 16;            
                newCap = DEFAULT_INITIAL_CAPACITY;
                //2-9. newThr = 12;
                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);
            }
            //2-10. threshold = 12
            //4-6. threshold=24
            threshold = newThr;
            @SuppressWarnings({"rawtypes","unchecked"})
            //2-11. 创建一个newTab=Node[16]的数组
            //4-7 把原来的数组扩展成一个newTab=Node[32]的数组
            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
            //2-12.table = newTab=Node[16] 主数组长度默认为16
            table = newTab;
            //4-8.进入if
            if (oldTab != null) {
                //4-9.oldCap = 16
                
                /*
                整个循环的意思就是对于之前数组中的元素再次根据e.hash & 数组.length公式算出在扩容后的数组的下标位置,
                    1.如果当前元素没有链表,则按照e.hash & (newCap - 1),算下标位置
                    2.如果当前元素下面有链表(链表里每一个元素都重新算),则按照e.hash & oldCap,算下标位置
                         2-1.如果算出(e.hash & oldCap) == 0,则还放在原来在老数组的对应下标位置;
                         2-2.如果算出(e.hash & oldCap) != 0,则放在j + oldCap的下标位置中;
                */
                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;
                        //1.8 引入的红黑树
                        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;
                            }
                        }
                    }
                }
            }
            //2-13. 返回一个长度为16的Node[]
            return newTab;
        }
        
         Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
            return new Node<>(hash, key, value, next);
        }
            
        final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
                                           int h, K k, V v) {
                Class<?> kc = null;
                boolean searched = false;
                TreeNode<K,V> root = (parent != null) ? root() : this;
                for (TreeNode<K,V> p = root;;) {
                    int dir, ph; K pk;
                    if ((ph = p.hash) > h)
                        dir = -1;
                    else if (ph < h)
                        dir = 1;
                    else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                        return p;
                    else if ((kc == null &&
                              (kc = comparableClassFor(k)) == null) ||
                             (dir = compareComparables(kc, k, pk)) == 0) {
                        if (!searched) {
                            TreeNode<K,V> q, ch;
                            searched = true;
                            if (((ch = p.left) != null &&
                                 (q = ch.find(h, k, kc)) != null) ||
                                ((ch = p.right) != null &&
                                 (q = ch.find(h, k, kc)) != null))
                                return q;
                        }
                        dir = tieBreakOrder(k, pk);
                    }
    
                    TreeNode<K,V> xp = p;
                    if ((p = (dir <= 0) ? p.left : p.right) == null) {
                        Node<K,V> xpn = xp.next;
                        TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
                        if (dir <= 0)
                            xp.left = x;
                        else
                            xp.right = x;
                        xp.next = x;
                        x.parent = x.prev = xp;
                        if (xpn != null)
                            ((TreeNode<K,V>)xpn).prev = x;
                        moveRootToFront(tab, balanceInsertion(root, x));
                        return null;
                    }
                }
            }
            
            final void treeifyBin(Node<K,V>[] tab, int hash) {
            int n, index; Node<K,V> e;
            if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
                resize();
            else if ((e = tab[index = (n - 1) & hash]) != null) {
                TreeNode<K,V> hd = null, tl = null;
                do {
                    TreeNode<K,V> p = replacementTreeNode(e, null);
                    if (tl == null)
                        hd = p;
                    else {
                        p.prev = tl;
                        tl.next = p;
                    }
                    tl = p;
                } while ((e = e.next) != null);
                if ((tab[index] = hd) != null)
                    hd.treeify(tab);
            }
        }
        
        void afterNodeAccess(Node<K,V> p) { }
        void afterNodeInsertion(boolean evict) { }
    }
    萝莉身,御姐心。。。。。
  • 相关阅读:
    Ubuntu adb devices :???????????? no permissions (verify udev rules) 解决方法
    ubuntu 关闭显示器的命令
    ubuntu android studio kvm
    ubuntu 14.04版本更改文件夹背景色为草绿色
    ubuntu 创建桌面快捷方式
    Ubuntu 如何更改用户密码
    ubuntu 14.04 返回到经典桌面方法
    ubuntu 信使(iptux) 创建桌面快捷方式
    Eclipse failed to get the required ADT version number from the sdk
    Eclipse '<>' operator is not allowed for source level below 1.7
  • 原文地址:https://www.cnblogs.com/bentuzi/p/15163065.html
Copyright © 2011-2022 走看看