JDK8 HashMap详解

HashMap简介    

     1.  HashMap什么场景下使用equals方法?

      HashMap是Java开发中最常用的容器之一,其中最常用的方法是put(K, V)和get(K)。大家都知道HashMap的K值是唯一的,可如何保证唯一性呢?首先想到的是用equals比较,没错这样可以实现,但随着内部元素的增多,put和get的效率将越来越低,这里的时间复杂度是O(n),假如有1000个元素,put时需要比较1000次。实际上HashMap很少会用到equals方法,因为其内通过一个哈希表管理所有元素,哈希是通过hash单词音译过来的,也可以称为散列表,哈希算法可以快速的存取元素,当我们调用put存值时,HashMap首先会调用K的hashCode方法,获取哈希码,通过哈希码快速找到某个存放位置,这个位置可以被称之为bucketIndex,通过上面所述hashCode的协定可以知道,如果hashCode不同,equals一定为false,如果hashCode相同,equals不一定为true。所以理论上,hashCode可能存在冲突的情况,有个专业名词叫碰撞,当碰撞发生时,计算出的bucketIndex也是相同的,这时会取到bucketIndex位置已存储的元素,最终通过equals来比较,equals方法就是哈希码碰撞时才会执行的方法,所以前面说HashMap很少会用到equals。HashMap通过hashCode和equals最终判断出K是否已存在,如果已存在,则使用新V值替换旧V值,并返回旧V值,如果不存在 ,则存放新的键值对<K, V>到bucketIndex位置。

    2.  HashMap为什么初始容量为2的幂?

      HashMap的数据结构是数组和链表的结合,所以我们当然希望这个HashMap里面的元素位置尽量分布均匀些,尽量使得每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的而不用遍历链表(理想状态下不需要通过equals去比较K),而且空间利用率最大。所以当HashMap的容量为2的幂的时候,不同的hash值发生碰撞的概率较小,这样就会使得数据在table数组中分布较均匀,查询速度也较快。若HashMap当前容量为2的幂,则经过扩容之后的HashMap的容量为当前容量的2倍(也是2的幂),HashMap的扩容后容量计算方法如下:

    //设置HashMap的最大容量
	static final int MAXIMUM_CAPACITY = 1 << 30;
	public static void main(String[] args) {
		int cap = 16; //设置HashMap的初始容量为16(默认最小值)
		int n = cap-1;	//n的二进制为:01111
		n = n | n >>> 1; //或号右边00111,左边01111,或运算之后01111
		n = n | n >>> 2; //此时n值为01111,或号右边00011,左边01111,或运算之后01111
		n = n | n >>> 4; //此时n值为01111,或号右边00000,左边01111,或运算之后01111
		n = n | n >>> 8; //此时n值为01111,或号右边00000,左边01111,或运算之后01111
		n = n | n >>> 16; //此时n值为01111,或号右边00000,左边01111,或运算之后01111
		if(n<0){
			n = 1;
		}else{
			if(n>MAXIMUM_CAPACITY){
				n = MAXIMUM_CAPACITY;
			}else{
				n = n + 1;
			}
		}
		System.out.println("最终n的值为:"+n);
		System.out.println("HashMap计算n的值为:"+tableSizeFor(16));
	}
	/**
	 * 根据输入初始化容量参数(最好是2的幂,可以充分利用Map的空间)cap,根据初始容量参数cap计算大于等于cap的最小2的幂的整数
	 * @param cap
	 * @return
	 */
	static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

3.  HashMap为什么初始加载因子为0.75?

        默认加载因子 (0.75) 在时间和空间成本上寻求一种折衷。加载因子太大虽然减少了空间开销,但一定程度也增加了查询成本和hash碰撞的几率;相反若加载因子设置太小则一定程度上增加了空间开销(resize会变得相对频繁)和hash碰撞的几率。

猜你喜欢

转载自blog.csdn.net/u011635492/article/details/80239181