Java中几种Map实现

Map是开发中经常用到的一种键-值对的存储结构,在java中有几种常用实现。
 

HashMap

HashMap允许值和value为null,线程不安全。
创建的时候通常用默认的构造方法,还有其他的构造方法可以设置初始大小和负载因子,不设置的话默认初始大小是16,设置的话要求最小是2的4次幂16,最大是2的30次幂,如果设置的值不是2的N次幂,会往上取离它最近的2的N次幂,负载因子是0.75f,当容量大于容器大小x负载因子就会扩容。
HashMap内部是通过Node<K,V>(也有可能是TreeNode,TreeNode是Node子类)数组来存储数据的,Node是一个链表,Node里有个Node类型的next变量。
向HashMap添加KV的时候,通过Key的hash%size,这样通过数组就能直接找到位置,如果该位置为null,则通过KV创建一个Node,放在数组的对应位置,如果该位置已经有个Node了,判断该Node是不是TreeNode,如果是,则按照红黑树的方式添加,否则按照Node方式添加,添加的时候会遍历链表,判断添加的key和当前Node的key是否相同或者equals为true,如果是,替换value,如果没有,则添加个新的Node。
这里开始是用Node链表实现的,当链表长度大于等于8,将链表转换成红黑树,因为链表过长,在get查询的时候耗时过长。
在计算位置的时候,先要计算hash值,hash是通过hashcode经过扰动函数计算出来的,hashcode是32位的二进制数,将自身右移16位与原值进行异或运算.
(h = key.hashCode()) ^ (h >>> 16)

来加大低位的随机性,并且混合后的低位也掺杂了部分高位的信息。

这是Java8的算法,Java7的算法要复杂些。
 
final int hash(Object k) {
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode();

        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

其实也是高低位混合。

数组的索引是通过hash%size计算的,用hash值对数组长度求模,可以保证该值在0和数组长度-1之间。
hashmap要求大小是2的N次幂,因为当size是2的N次幂时,hash%size=hash&(zise-1),可以用与运算代替模运算,提高计算速度。
因为2的N次幂的二进制都是1+n个0,乘以2就是1左移1位,这里假设有一个hashcode值,假设当前size是32
hashcode = 1111 1111 1111 1111 1100 1001 1110  1000 
size = 10 0000

可以发现hashcode对应size的1左边的值肯定是可以被size除尽的,那么hashcode%size的结果其实就是hashcode最左边的5位,所以和hashcode&(size-1)是相等。

HashTable

HashTable的key和value都不允许为null,初始容量为11,扩容时,以原容量2倍+1进行扩容,因为其容量不是2的N次幂,所以只能用模运算计算位置,这比hashmap要慢,HastTable是线程安全的,每个方法都有synchronized修饰。相对于HashMap来说HashTable的唯一优势就是线程安全,但是性能并不高,如果需要线程同步,可以使用ConcurrentHashMap.

ConcurrentHashMap

ConcurrentHashMap实现了ConcurrentMap接口,ConcurrentMap又实现了Map接口,所以ConcurrentHashMap也是Map的一种实现。它的大小和扩容机制都和HashMap一样,存取也差不多,区别就是put的时候为了线程安全会加锁,但是不是像HashTable那样整体加锁,而是对key对应的node加锁,这样如果两个线程同时put,如果根据key计算的位置不同是完全不影响,只有两个key经过hash扰动并求模后的值仍然一样时才会等待。
 
 
 
 
 
 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值