hashmap 和 linkedhashmap区别

    hashmap是最常用不过的数据结构了,里面的有些小细节还是不那么清晰,在此整理了一下,供大家参考。

1. hashmap的初始容量为什么是2的N次方?

    解答:不是2的N次方是不是可以?当然可以。这个2的N次方是初始化谁的?是初始化哈希数组的,也就是每个key值对应的地方。只不过这里做了优化,代码一目了然:

 /**
     * Returns index for hash code h.
     */
    static int indexFor(int h, int length) {
        return h & (length-1);
    }

2的N次方-1,最后就变成了一堆的1。比如2的4次方是16,那么16-1=15的二进制表示就是1111 1111  这样再用&运算,速度快而且不会越界。


2. hashcode为何要以31作为一个因子来计算?

    解答菜参考了几篇比较好的帖子,总体理由如下:31是素数,减少相同key值碰撞可能;经过实验验证,31相对稳定。当然,不排除后续会用更大的素数来替代;我们注意到hashcode用int类型存储,肯定存在越界可能,但是没关系,变成负数或者数据被移除不影响读取。

 

3. hash(int)里面一堆的运算符是干嘛的?

   解答:

hash ^= (hash >>> 20) ^ (hash >>> 12);
int h = hash ^ (hash >>> 7) ^ (hash >>> 4);

为什么要经过这样的运算呢?这就是HashMap的高明之处。先看个例子,一个十进制数32768(二进制1000 0000 0000 0000),经过上述公式运算之后的结果是35080(二进制1000 1001 0000 1000)。看出来了吗?或许这样还看不出什么,再举个数字61440(二进制1111 0000 0000 0000),运算结果是65263(二进制1111 1110 1110 1111),现在应该很明显了,它的目的是让“1”变的均匀一点,散列的本意就是要尽量均匀分布。

4. Entry为何要定义为HashMap中的内部类?引申一下,什么时候用内部类?

    解答:内部类可以访问类的私有成员,而且通常表明该内部类隶属于主类的关系。更多是从架构考虑

5. 为何LinkedHashMap可以按照插入顺序或者访问顺序读取?而HashMap不可以?

   解答HashMap的读取是从table[0]顺序遍历到table[length-1],对于table[i]的数据链表如果不为空则输出,这样无法保证你插入的顺序。比如你先插入的是  "a":"value"后插入“b”:"value"。而key "b"放在table[4]的位置,key "a"放在table[7]的位置,那么读取的时候肯定是"b"先被读出来,因为按照table[i] i 递增读取;

  LinkedHashMap维护了一个双向链表并且重写了Entry和addEntry方法,使得每次增加都会在双向链表中插入一个值。当遍历的时候只需要从双向链表顺序读取就可以了,访问要比HashMap快。当然,写入和存储的成本要比HashMap高。



参考文献:

http://www.javamex.com/tutorials/collections/hash_function_technical_2.shtml

http://www.cnblogs.com/hzmark/archive/2012/12/26/LinkedHashMap.html

http://www.cnblogs.com/hzmark/archive/2012/12/24/HashMap.html

http://www.iteye.com/topic/838030


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值