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

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

  • 相关阅读:
    手机网页唤醒app,
    h5 audio进度条
    js判断字符串与字符串相互包含,以及数组是否包含某个元素;
    vue cli 打包项目造成css背景图路径错误
    vue-cli webpack打包不.map文件,iview 项目打包完,图标路径有问题
    常用的活动榜单
    vue-cli的webpack模板项目配置文件分析,配置信息详解
    eclipse怎么debug项目
    什么是前置机,前置机的作用是什么
    jsp中连接数据库及实现增删改查
  • 原文地址:https://www.cnblogs.com/zyx1314/p/5359434.html
Copyright © 2011-2022 走看看