一、Java容器
Java的集合类主要由collection和map(具有映射关系的集合)这两接口派生而出,其中collection又派生出三个子接口,分别是set(无序的,元素不可重复的集合)、list(有序的,元素可以重复的集合)、Queue(队列)
collection体系的继承数如下:
map体系的继承树如下:
记录一下map的put过程:
从hashmap的角度看put的过程
1、首次扩容:先判断数组是否为空,若数组为空进行第一次扩容(resize)
2、计算索引:通过hash算法,计算键值对在数组中的索引
3、插入数据:如果当前位置的元素为空,则直接插入数据;若K非空,V存在则覆盖V;如果K非空,V不存在则将数据接到链表末端;若链表长度达到8,则将链表转化为红黑树,并将数据插入树中
4、在此扩容:如果数组中元素个数超过阈值(threshold),则在此进行扩容操作
hashmap的特点:
1、HashMap是线程不安全的实现
2、HashMap可以使用null作为key或value
JKD7与JDK8中的HashMap有什么区别
1、JDK7中的HashMap是基于数组+链表实现的,它的底层维护是一个Entry数组,它会根据计算的hashCode将对应的KV键值对存储到该数组中,一旦发生hashCode冲突,那么就会将该KV的键值对放到对应的已有元素的后面,此时便行程了一个链表式的存储结构
2、显然这个链表会越来越长,最后效率就很差了,所以JDK8做了一个处理,就是当链表的长度大于等于8的时候漫步在采用链表存储而是采用红黑树,这样查询一直维护在0(logn)
HashMap的实现原理
1、它是基于hash算法,通过put方法和get方法存储和获取对象
2、存储对象时,我们将KV传给put方法是,它调用Kde hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前的bucket的占用情况自动调整容量(超出LoadFactor就扩容到原来的2倍),获取对象时,我们把K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确认键值对
3、如果发生碰撞则通过链表组织数据,当链表长度过长,则转化为红黑树,这个在前面说过了
介绍一下HashMap的扩容机制:
1、数字的初始容量是16,而容量是以2的次方扩充的,一是为了提高性能,二是为了能使用位运算替代取模运算(因为容量是一个2的倍数)
2、数组是否需要扩充是通过负载因子判断的,如果当前元素个数为数组容量的0.75时,就会扩充数组。这个0.75就是默认的负载因子,可由构造器传入。我们也可以设置大于1的负载因子,这样数组就不会扩充,牺牲性能节省内存
3、为了解决碰撞,数组中的元素是单向链表类型,当链表阈值达到一个阈值(8),会将链表转换成红黑树提高性能,降到6的时候又会将红黑树装换回单向链表以提高性能,这里有一个缓冲的7就是为了防止在两种数据结构之前反复转化导致性能退化
4、扩容的时候通过监测当前的哈希值最高位是0还是1来判断要不要往前移动,因为我们之前是取了模的,有可能某些高位被忽略掉了,现在又拿了出来,如果是1则往前移动2的len-1个单位,如果是0不移动
HashMap中的循环链表式如何产生的: