文章目录
集合分为两大类:一类是单列集合,一类是双列集合
单列集合
单列集合是实现Iterable接口产成的对象,支持迭代器和增强for。
1. ArrayList
特点:有序(存取有序)且可重复, 这个数组的初始长度是0,第一次添加元素的时候会初始化容量为10;在1.7之前是构造ArrayList时
就默认开辟10个空间;arrayList底层是一个Object数组结构,因为是数组结构,所以它是有索引的,因此它的查询速度很快,但是在增
删的时候,需要调整数组元素的移动,所以增删比较慢;查阅源码可以得知它存储数据到11的时候,数组会进行扩容。扩容大小是原来的
1.5倍,在整个add的过程中,数组没有对数据进行元素的判断,所以arrayList是可重复的;
2. LinkList
特点:有序(存取有序)且可重复;
LinkList是一个双向链表的结构,它存储的结构是通过节点之间的一个指向进行链接的,因此每次查询时都要从两头进行查询(离头近就
从头查离尾近就从尾查),所以查询较慢,但是增删的时候,只需要将链表头节点和尾节点指向新插入的节点即可,所以增删速度较快;
这个集合也是一个有序且可重复的集合,因为它也没有对一个对元素的判断;
LinkList的增删快,为什么不使用LinkList进行存储,因为LinkList占内存
ArrayList和LinkList有什么区别?
ArrayList在进行查询的时候,效率明显比LinkList快,LinkList在进行无规则的插入的时候效率会比ArrayList快;因为ArrayListr底层
数组的扩容是1.5倍,数据量越大,扩容的速度就越快,而链表仍需一个个断开链接和重续新链接。
3. HashSet
特点:无序且不可重复
hashSet底层是HashMap中的key进行存储的
所以就需要讲到Map集合,HashMap集合 ---------->> 转到HashMap
4. copyonwriteArrayList
注:arrayList在进行遍历时不允许增删改:会出现ConcurrentModificationException(并发修改异常)
换一个可以并发的类(copyonwriteArrayList)
双列集合
1. HashMap
1.7 之前
HashMap中1.7之前它的底层是数组+链表的结构,它的存储特点是key是无序的且不可重复的,可以存null,存储value没有特点,想存什
么就存什么;1.7的初始长度是0,初始容量是16,因为2个幂次方在位运行的情况下效率最高;扩容大小是原来的2倍,扩容时机是当存
储个数>=扩容阈值&&hash冲突(存储位置有元素),需要注意的一点是:hashMap扩容是非常损耗性能的,需要把老数组的所有元素和
新元素全部计算一次新的hash,所以如果已知需要存储的元素个数,那么最好初始化直接构建。
1.7的执行原理:
-
存储元素时,首先判断key是不是null,如果是则变为头节点
-
不是null时再根据key计算hash,根据hash和数组长度计算下标
-
根据计算出来的下标获取下标元素,如果获取到的元素不为null,判断hash是否相等,eq是否相等,==是否相等,如果都相等则替换value
-
如果不相等,根据头插法插入到链表中(hash冲突的现象)
HashMap出现的问题
- 线程安全问题,会丢值
- 会出现环链问题——原因:头插法 (这里有问题)
- 链表过长,导致性能变低
面试问题:
为什么一个节点存储存储12个元素
hashMap在极端情况下可以存储多少个元素不扩容?
一个节点最大存储的元素是 >=12个,存储元素的当前位置有值(hash冲突)
1.7HashMap的初始容量是16,所以15+12=27
1.8 之后
- 引入红黑树解决了链表过长的问题
- 尾插法和红黑树,解决了环链的问题
1.8 HashMap的结构是数组+红黑树,
为什么引入红黑树
解决了链表过长的问题,提升了查询效率
为什么不直接使用红黑树
- 节点少的时候,链表和红黑树的差距不大;
- 红黑树是以空间换时间
- 数组大于8时会变成红黑树
- 数组小于6时会变成链表
- 从8删除到7时,7是红黑树;从6增加到7时,7是链表
为什么树化值是8
因为有个算法是泊松算法分布计算得到的,hash冲突8次的概率是千万分之一
1.8 链表添加元素用的是尾插法,1.8 hashMap存储第13个值必扩容
如果数组长度<64出现红黑转换的情况,那么不会出现红黑树,而是进行数组扩容
尾插法和红黑树解决了环链的问题
2. concurrentHashMap
1.7 Segment分段锁机制
1.8 CAS + SYN