常见Map最清晰明了的描述

 

HashMap:

数组+链表+红黑树(jdk8 链表数大于8,转为红黑树存储)

数组权当hash桶,链表或红黑树为桶里的数据,通过对key进行hash及取模获取到数组下标,然后在数组下标获取对应的链表或红黑树,进行插入、查询、删除操作。

上边的通过对key进行hash及取模获取到数组下标分析:

jdk7 

key.hash&(capacity-1)  (说明:此处是二进制与计算,其实就是对key的哈希值进行取模。等同于10进制计算 key.hash % capacity的效果,但是效率比这高。其实都是为了获取0到capacity-1的一个值。)

源码:

static int indexFor(int h, int length) {    

     return h & (length-1);    

 }  

注:capacity为容量,默认容量为16,扩容时2倍扩容。及capacity始终为2的幂次方。因为2的幂次方减一 二进制都为 1111...111(位数为x),进行与计算时,结果就为key的hash值后x位数的值。所以只要保证hash是均匀分布的,就可以保证取的数组下标是均匀分布的。可以尽量避免hash冲撞问题(即不同key所取数组下标相同)。

 jdk8

因为jdk8加入红黑树逻辑,所以hash冲撞时性能影响不大。因此key.hash时,只取了前16位异或下来的数据(异或的操作是相同为0 不同为1,即将前16位二进制全变为0,只剩下其余的二进制值);key的hashcode二进制位数小于16位的,计算出来的下标值都为0。

源码:

jdk8去掉了indexFor方法,直接在代码里写的(tab.length-1)&hash (注:类似于该种格式,可能是(n - 1) & hash ,其中n赋值了tab.length)

key获取hash方法:

static final int hash(Object key) {

        int h;

        return (key == null) ? 0 : (h =key.hashCode()) ^ (h >>> 16);

    }

相关文章: