zoukankan      html  css  js  c++  java
  • java HashMap

    HashMap 的性能因子

    1. 容量:表示桶位的数量。

    2. 初始容量: 表在创建是所拥有的桶位数。

    •   如果你知道将要在HashMap存储多少项,创建一个初始容量合适的HashMap将可以避免自动再散列的开销
        /**
         * The default initial capacity - MUST be a power of two.
         */
        static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //默认大小

    3. 尺寸: 表中当前存储的项数。

    4. 负载因子:尺寸/容量。 负载因子小的表冲突的可能性小,插入和查找的速度也相对较快(但会减慢使用迭代器进行遍历的过程)。HashMap和HashSet都具有允许你指定负载因子的构造器,表示当负载情况达到负载因子的水平时,容器将自动增加容量。实现方法是使容量加倍,并将现有对象分配到新的桶位集中。

        /**
         * The load factor used when none specified in constructor.
         */
        static final float DEFAULT_LOAD_FACTOR = 0.75f;

    HashMap构造器

    HashMap(int initialCapacity, float loadFactor);
     initialCapacity为初始容量, loadFactor为负载因子
           /**
          * Constructs an empty <tt>HashMap</tt> with the specified initial
          * capacity and load factor.
          *
          * @param  initialCapacity the initial capacity
          * @param  loadFactor      the load factor
          * @throws IllegalArgumentException if the initial capacity is negative
          *         or the load factor is nonpositive
          */
        public HashMap(int initialCapacity, float loadFactor) {
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal initial capacity: " +
                                initialCapacity);
            if (initialCapacity > MAXIMUM_CAPACITY)  // 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); // tableSizeFor(initialCapacity) 会返回x(x表示2的整数次幂)
            //threshold是一个阙值,它等于 负载因子*尺寸, 当然这里暂时等于容量
            //当调用resize函数后才开始真正分配空间(槽位),这时才赋给threshold真正意义上的值
        }

    来看看tableSizeFor的实现(个人绝对想不到这么高大上的方法)

        /**
         * Returns a power of two size for the given target capacity.
         */
        static final int tableSizeFor(int cap) {
            int n = cap - 1;  //这里是因为考虑到cap为2的整数次幂的情况
    
            //1. 假设此时n的二进制最高位1在第i位(最低位为第0位)
    
            n |= n >>> 1;
    
            //2. 此时n的二进制第i, i-1位都为1
    
            n |= n >>> 2;
    
            //3. 此时n的二进制第i, i-1,  i-2, i-3位都为1
    
            n |= n >>> 4;
    
            //4. 此时n的二进制第i, i-1,  i-2, i-3, i-4, i-5, i-6, i-7位都为1(当然,严谨点应该再假设i>7)
    
            n |= n >>> 8;
            //5.---------
            n |= n >>> 16;
            //6.---------
            return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
        }

    添加元素

        public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
    
        /**
         * Implements Map.put and related methods
         *
         * @param hash hash for key
         * @param key the key
         * @param value the value to put
         * @param onlyIfAbsent if true, don't change existing value
         * @param evict if false, the table is in creation mode.
         * @return previous value, or null if none
         */
        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);  // 没反生冲突,直接放入第i个槽位
            else {
            //执行到这里,表示发生冲突了
                Node<K,V> e; K k;
                if (p.hash == hash &&
                        ((k = p.key) == key || (key != null && key.equals(k))))
                    e = p;  //如果key相等,直接把新value覆盖原value
                else if (p instanceof TreeNode) //判断当前解决冲突所用的数据结构是不是TreeNode(红黑树)
                                                //这是当冲突过多(某个槽位冲突数超过TREEIFY_THRESHOLD=8)时,
                                                //HashMap的优化方式
                    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) // 冲突数超过TREEIFY_THRESHOLD
                                                                   // 用红黑树代替链表
                                treeifyBin(tab, hash);
                            break;
                        }
                        if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k))))
                            break;
                        p = e;
                    }
                }
                if (e != null) { //如果map存在与新key相等的key,直接把新value覆盖原value
                    V oldValue = e.value;
                    if (!onlyIfAbsent || oldValue == null)
                        e.value = value;
                    afterNodeAccess(e);
                    return oldValue;
                }
            }
            ++modCount;
            if (++size > threshold) //判断当前尺寸是否大于阙值(即负载是否大于负载因子)
                resize();
            afterNodeInsertion(evict);
            return null;
        }

    博客园(FOREVER_ENJOY):http://www.cnblogs.com/zyx1314/p/5359434.html

    本文版权归作者所有;欢迎转载!请注明文章作者和原文连接

  • 相关阅读:
    LeetCode题解之Flipping an Image
    LeetCode 之Find Minimum in Rotated Sorted Array
    LeetCode题解Transpose Matrix
    LeetCode 题解之Minimum Index Sum of Two Lists
    LeetCode题解之Intersection of Two Linked Lists
    LeetCode 题解之Add Two Numbers II
    LeetCode题解之Add two numbers
    href="#"与href="javascript:void(0)"的区别
    有关ie9 以下不支持placeholder属性以及获得焦点placeholder的移除
    ie7下属性书写不规范造成的easyui 弹窗布局紊乱
  • 原文地址:https://www.cnblogs.com/zyx1314/p/5359434.html
Copyright © 2011-2022 走看看