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

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

posted @ 2016-04-06 15:11  ForeverEnjoy  阅读(941)  评论(0编辑  收藏  举报