HashMap的特性
HashMap存储的是键值对 值允许为null key值不可重复 如果重复 value将被覆盖
非同步 线程不安全 无序
底层原理
jdk8后采用的是:数组+链表+红黑树
当使用put方法时,会先对key做一个hashcode值计算,找到在bucket数组中的位置,来存储Entry对象;如果hashcode值相同就通过equals方法进行比较;如果equals方法返回false,就将数据以链表的形式存储在数组对应的位置,并将之前在该位置的数据往链表的后面移动(头插法),并记录一个next属性,来指示后移的那个数据。
当使用get方法时,同上
头插法
HashMap会将Entry对象不断插入链表的头部,这样也防止来尾遍历,否则Entry每次添加还要定位到尾节点。如果条件竞争(多线程操作),可能会出现环形链表,当使用get操作时,有可能发生死循环。
put方法如何实现
1.计算key的hashcode值
2.如果散列表为空的时候,调用resize()方法初始化散列表
3.如果么有发生碰撞 直接将元素添加到散列表
4.如果发生了hah碰撞,进行判断 如果key值相同 替换value值 如果是 链表的结构 在链表的尾部进行插入,如果链表个数达到红黑树的阈值8 转为黑树结构 如果是红黑树结构 调用树的插入方法
5.如果元素总数大于阈值 就会调用resize()方法进行扩容
扩容实现resize()方法
默认负载因子大小为0.75,当一个map填满75%的bucket时,将会创建原HashMap2倍大小的bucket,并将原来的对象重新计算放入新的bucket中。
哈希碰撞
key值不同 但是通过hashCode计算的值却是一样,,,发生碰撞以后 HashMap使用LinkedList来存储对象(键值对)
为什么引入红黑树
jdk1.8以前 数据结构是数组 +链表
当hashMap中大量的数据都存放到一个桶里的话 这个通就会很大 时间遍历的复杂度是0(0) 针对这种问题 引入了红黑树来优化
为什么String integre这样的wrapper类适合的作为主键
String是不可变得类 String/Integre都重写了hashCode和equals方法 。如果使用对象的话 就需要再重写其hashCode方法和equals方法 并且这个对象是不可变的。。