1. ArrayList
可变数组 非同步(不安全,效率高) 允许null
查询快,增删慢(移动大量元素)
扩容:ensureCapacity(int minCapacity) Arrays.copyOf(elementData, newCapacity);
底层为System.arraycopy(a, 0, elementData, index, numNew);
原数组拷贝一份到新数组,容量增长为原来的1.5倍
Fail-Fast机制,并发修改时,迭代器很快完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险
remove() 下标到数组末尾的元素向前移动一个单位,并把最后一位的值置空,方便GC
2. LinkedList
双向循环链表 非同步(不安全,效率高) 允许null
查询慢,增删快(有指针)
节点:前指针、数据、后指针
为什么基于双向链表,而不是单向?方便插入和删除!
addFrist(E e) :header元素的下一个元素前插入
addLast(E e):header元素之前插入
分两半查找,先判断index是在链表的哪一半,然后再去对应区域查找,这样最多只要遍历链表的一半节点即可找到
3. HashMap
哈希表 非同步(不安全,效率高) 允许null键和null值,不保证映射的顺序
数组+单链表(每一个数组元素) 当链表长度大于一定阈值时,链表转换为红黑树,这样减少链表查询时间。
1)HashMap底层采用一个Node[]数组来保存所有的key-value对,当需要存储一个Node对象时,会根据key的hash算法确定在数组中的存储位置(下标),再根据equals方法确定该数组位置上的链表中的存储位置(如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。);当需要取出一个Node时,根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Node。
2)扩容需要重新计算扩容后每个元素在数组中的位置,很耗性能。
当HashMap中的元素个数超过数组大小*loadFactor(默认值为0.75)时,默认情况下,数组大小为16,当HashMap中元素个数超过16*0.75=12的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置。
3)Fail-Fast机制,通过一个modCount值记录修改次数,对HashMap内容的修改都将增加这个值。迭代器初始化过程中会将这个值赋给迭代器的expectedModCount,在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map,马上抛出异常
4. Hashtable
哈希表 同步 (安全,效率低) 不允许null键和null值,不保证映射的顺序
数组+单链表(每一个数组元素)
1)Hashtable底层采用一个Entry[]数组来保存所有的key-value对,当需要存储一个Entry对象时,会根据key的hash算法来决定其在数组中的存储位置(下标),再根据equals方法决定其在该数组位置上的链表中的存储位置(如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。);当需要取出一个Entry时,也会根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。
2)synchronized是针对整张Hash表的,即每次锁住整张表让线程独占。
5. ConcurrentHashMap
1) 与HashMap不同的是,ConcurrentHashMap使用多个子Hash表,也就是段(Segment)
2) 允许多个修改操作并发进行,锁分离技术:使用多个锁来控制对hash表的不同段的修改,每个段其实就是一个小hashtable,它们有自己的锁。只要多个并发发生在不同的段上,它们就可以并发进行。
3) 多个读操作并发进行,读操作并不需要加锁。HashMap中在hash链的中间添加或删除元素,读操作不加锁将得到不一致的数据。ConcurrentHashMap实现技术是保证HashEntry几乎是不可变的。
4) 存储与取出同hashtable
6. LinkedHashMap
继承HashMap,哈希表+双向链表(保证有序性) 非同步 (不安全,效率高) 允许null键和null值
基本操作与父类HashMap相似,通过重写HashMap相关方法,重新定义了数组中保存的元素Entry,来实现自己的链接列表特性。该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而构成了双向链接列表。
7. HashSet
哈希表 允许null值元素
基于HashMap实现(HashMap的一个实例)
8. LinkedHashSet
继承HashSet,操作类似
基于LinkedHashMap实现,存储元素