ArrayList和LinkedList的区别?
两者都实现了 List接口,两者都是线程不安全的(Vector是线程安全的)
区别:
- 底层数据结构不同:
- ArrayList使用动态数组实现,通过索引进行快速访问元素
- LinkedList使用双向链表实现,通过节点之间的指针,进行元素的访问和操作
- 插入和删除操作的效率不同:
- ArrayList在尾部的插入和删除操作效率较高,但在中间或开头的插入和删除效率较低,需要移动元素
- LinkedList在任意位置的插入和删除操作效率都比较高,因为只需要调整节点之间的指针,但是LinkedList是不支持随机访问的,所以除了头节点外,插入和删除的时间复杂度都是0(n),效率也不是很高,所以LinkedList基本没人用
- 随机访问效率不同:
- ArrayList支持通过索引进行快速随机访问,时间复杂度为O(1)
- LinkedList需要从头或尾开始遍历链表,时间复杂度为O(n)
- 空间占用:
- ArrayList在创建时需要分配一段连续的内存空间,因此会占用较大的空间
- LinkedList每个节点只需要存储元素和指针,因此相对较小
- 使用场景:
- ArrayList适用于频繁随机访问和尾部的插入删除操作
- LinkedList适用于频繁的中间插入删除操作和不需要随机访问的场景
ArrayList扩容机制说一下?
ArrayList在添加元素时,如果当前元素的个数达到了内部数组的容量上限,就会触发扩容操作
ArrayList扩容操作的主要内容:
- 计算新的容量:一般情况,新的容量会扩大为原来的1.5倍,然后检查是否超过了最大容量限制
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* 最小增长 */
oldCapacity >> 1 /* 首选增长 */);
- 创建新的数组:根据得到的容量,创建一个更大的新数组
- 将元素复制:将原来数组中的元素逐个复制到新数组中
- 更新引用:将ArrayList内部指向原数组的引用指向新数组
- 完成扩容:扩容完成后,可以继续添加新元素