HashMap小结

踏踏实实积累,不要浮躁!!!

1:为什么用HashMap

  • HashMap 是一个散列桶(数组和链表),它存储的内容是键值对(key - value)
  • HashMap采用了数组和链表的数据结构,能在查询和修改方面继承了数组的线性查找和链表的寻址修改
  • HashMap是线程不安全的
  • HashMap可以接受null键和值,而HashTable不能

解释为什么 HashMap可以接受 null 键和值

a:如果 k 值传入的是 null ,得到的hash 值是0

b:解析 HashMap put的源码逻辑   TODO

 

 

2:HashMap工作原理 ?

HashMap是基于hashing的原理,我们使用put(key,value)存储对象到HashMap中,使用 get(key)从HashMap中获取对象,调用Put方法时通过key的hashcode值找到Map数组的bucket位置来存储Node对象,具体流程如下

  • 1:对key求Hash值,然后计算下标
  • 如果没有碰撞直接放入桶中
  • 如果发生碰撞,以链表的方式放在后面(用链表法来解决冲突)
  • 如果链表长度超过阀值  TREEIFY_THRESHOLD(8) 会改造成 rbTree 当元素个数小于6的时候又转换成链表
  • 如果节点已经存在,会替换原来的value值
  • 如果 桶满了(初始容量16 * 负载因子0.75)就需要 resize操作 扩容到之前的两倍 

3:有什么方法可以减少碰撞

  • 扰动函数可以减少碰撞,尽量确保两个不相等的对象返回不同的hashcode,这样能减少碰撞的几率(扰动函数其实就是Hash函数内部的实现原理 TODO 里面具体的实现细节还不清楚)
  • 使用不可变的,声明为final的对象做key,并且采用合适的hashcode和equals方法,在hashmap中Keyi值不可变是必要的

4:HashMap中 hash函数的实现

static final int hash(Object key) {
    if (key == null){
        return 0;
    }
     int h;
     h=key.hashCode();返回散列值也就是hashcode
      // ^ :按位异或
      // >>>:无符号右移,忽略符号位,空位都以0补齐
      //其中n是数组的长度,即Map的数组部分初始化长度
     return  (n-1)&(h ^ (h >>> 16));
}

解释:

1:求出key的hash值

2:将hash值高16位不变,低16位与高16位取异或

3:n表示桶的长度,通过(n -1) & 上面取的值 得到桶的序号  (其实就是取模这种方式更高效)

 

5:为什么不用二叉查找树,而用红黑树

红黑树可以解决 二叉查找树,在特殊情况下性能退化的问题(可能会退化成链表,查找的时间复杂度O(n)),

 

6:说说你对红黑树的见解

  • 每个节点非黑即红
  • 根节点是黑色的
  • 如果节点是红色的,那么子节点一定时黑色的,反之不一定
  • 每个叶子节点都是黑空
  • 从根节点到叶子节点的路径,每条路径都包涵数目相同的黑色节点(黑色高度相同)

 

7:HashMap什么情况下会发生死循环

TODO

 

 

 

8:CurrentHashMap 原理

 

  • 最大的特点是引入了 CAS (compare and swap)借助Unsafe来实现,采用cpu指令来保证 (CAS操作的过程,内存值V,旧的预期值A,要修改的新值B 当且仅当预期值A和内存值V相等时才会将B值更新到V值中去)
  • 分段锁   降低了锁的粒度
  • TODO

TODO

9:CAS操作会出现的问题

TODO

 

 

 

10:能用currenthashmap代替hashtable嘛 ?

可以的

 

 

11:currenthashmap在java8中有个bug,会进入死循环

原因是递归创建currenthashmap对象,该bug在1.9已经修复

场景重现如下

public class ConcurrentHashMapDemo{

    private Map<Integer,Integer> cache =new ConcurrentHashMap<>(15);

    public static void main(String[]args){
        ConcurrentHashMapDemo ch =    new ConcurrentHashMapDemo();
        System.out.println(ch.fibonaacci(80));
    }

    public int fibonaacci(Integer i){
        if(i==0||i ==1) {
            return i;
    }

    return cache.computeIfAbsent(i,(key) -> {
        System.out.println("fibonaacci : "+key);
        return fibonaacci(key -1)+fibonaacci(key - 2);
    });

    }
}

TODO 原因解释  ??? 

 

12: JDK9怎么解决上面这个死循环的BUG ?

 

 

 

 

 

 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值