HashMap:是Key-Value样式
底层是数组加链表的样式,后面改为数组+链表+红黑树的存储方式
数组是主体,如果本身创建的时候没有指定大小则默认大小为16。
得到key值对应的hashcode,运用位与运算计算该key值对应的数组下表,循环该位置的链表,使用eques方法比较链表中的key值,如果找到跟输入的key相同的值,则替换value值为新的value值,如果没找到,则在链表中插入。
当容量到大阈值,即数组大小*负载因子,则需要扩容,将扩展为当前数组容量的2倍。将原来的元素通过计算新的哈希值散列到新生成的数组上(数组的每个元素也叫桶)
当初始化hashmap容量的时候,初始化的是数组的大小
当链表长度为8时转换为红黑树,当桶中元素小于等于6时会转换为链表
HashSet:不重复的无需集合
HashSet的底层就是HashMap结构,向HashSet中插入的值,就是hashMap中的key值,因为,hashMap中的key值不能重复,所以hashset是不能重复的集合,因为hashMap中的元素是无序的,所以HashSet中的值也是无序的
ArrayList:有序可以重复集合
ArrayList底层是数组,默认大小是10,数组大小不够用时,是将数组扩容成目前容量的1.5倍。然后将久数组的元素挪到新数组中。使用Arrays.copyOf();方法
当想固定位置插入元素的时候,是将该位置的值向后挪一位,删除某个位置的值的时候,是将该位置后面的值向前挪一位
因为底层是数组,所以元素可以重复,且有序
LinkedList:有序的可重复的集合
LinkedList底层是双向循环链表且头节点中不存放值,没有长度的概念,没有初始化的默认大小
插入时,默认插入到最后一位,删除时,需要遍历与需要删除字段相同的值
当删除固定位置时,先判断该位置与size/2的大小,如果比size/2大,则从size/2的位置开始遍历,如果比size/2小,则从0开始遍历
HashTable的方法都使用synchronize修饰,效率底下
concureentHashMap线程安全的HashMap
volatile int sizeCtl;控制状态,如果小于0表名正在初始化,则线程阻塞,否则cas更换更换
- put()要求键值都不能为空
- 需要经过两次散列, 是数据均匀分散,减少碰撞的次数
- 判断tab是否进行了初始化,没有则调用initTable进行初始化操作(单线程)
- 数组i的位置没有元素存在,直接放入
- 如果i的位置在进行MOVE操作,也就是在进行扩容操作,则多线程帮助扩容
- 如果i的位置有元素存在,则在该节点加锁Synchronized,判断是链表还是红黑树,按照相应的插入规则插入
- get方法:
- 根据传入的key,获取相应的hash值
- 然后判断当前的table数组是否为空
- 计算指定的key在table中存储的位置
- 链表或者红黑树转换相依的方法处理
- 不存在则返回null