关于HashMap容量-JDK15浅析

HashMap容量

HashMap是啥~~~
以下是来自JDK15源代码中的定义:

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable

在集合框架中,把Map接口实现并继承了AbstractMap,所以是一个类

继续往下读这个类,第一个属性定义源码如下:

 /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
     * The maximum capacity, used if a higher value is implicitly specified
     * by either of the constructors with arguments.
     * MUST be a power of two <= 1<<30.
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;
//最大容量为2^31;原因如下,size都只是定义为int型
/**
     * The number of key-value mappings contained in this map.
     */
    transient int size;

默认初始化容量为16,而且必须初始化为2的n次幂,此处我试了一下,并不是指实例化时必须传一个2次幂整数作为参数。传入初始化容量后,它实际会调用一个修正函数:

    /**
     * Returns a power of two size for the given target capacity.
     */
    static final int tableSizeFor(int cap) {
        int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
个人解读:
n = -1 对应二进制1111 1111 1111 1111
    
numberOfLeadingZeros方法给定一个int类型数据,返回这个数据的二进制串中从最左边算起连续的“0”的总数量。
    
也就是找到遇到第一个1,左边(高位)有多少1,比如9的二进制100132int表示的话,高28位都为0
    
>>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0
    
然后n得到的应该是一个大于等于n的数。
    
理由:
    1.如果cap是2的次幂,如2^x次幂,那么2^x-1应该是x个1(最低位),那么实际n逻辑右移后得到的就是2^x-1
    比如给160000 0000 0001 00001得到:   					0000 0000 0000 1111
    调用numberOfLeadingZeros得到 :	28
    完后:-1 >>> 28得到 				0000 0000 0000 1111
    
    2.如果不是2的次幂,那么得到的就是大于cap的最小的2次幂

return语句两个 ? : 运算符
第一个判断n和0的关系,如果n小于0,那么就返回1,否则还得比较一下有没有超过允许的1最大容量,不超过返回n+1

通过高效位运算就完成了容量修正。但是好像并不能直接通过方法返回容量。

查看HashMap有参构造函数:

/* ---------------- Public operations -------------- */

    /**
     * Constructs an empty {@code HashMap} 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)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

threshold字段存容量~~~,没方法直接获取这个指。

突然想起看过反射了,还没用过。试一试!!!

走起~

public class Main {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException {

        HashMap<String,Integer> hm = new HashMap<String,Integer>(10);
        //实例的getClass方法获取Class
        Class<?> myhash = hm.getClass();
        //获取指定属性,也可以调用getDeclaredFields()方法获取属性数组
        Field threshold =  myhash.getDeclaredField("threshold");
        //将目标属性设置为可以访问
        threshold.setAccessible(true);
        System.out.println(threshold.get(hm));
    }
}

传参初始化容量为10,不出意外应该输出16

在这里插入图片描述

有警告,说是JDK版本太高~~~,但却是输出了16。

put方法

index = HashCode(Key) & (Length - 1)

可以说,Hash算法最终得到的index结果,完全取决于Key的Hashcode值的最后几位。

如果Length - 1不是全1的二进制,映射方法不平均,好像根据什么泊松分布得出的结论。

显然不符合Hash算法均匀分布的原则。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值