ArrayList和LinkedList的区别、扩容机制及底层的实现方式是什么
更新时间:2023-09-15ArrayList和LinkedList的区别
ArrayList和LinkedList都是Java集合框架中的List接口的实现类,它们有各自的优缺点和适用场景。
ArrayList是基于动态数组实现的,它的内部使用数组来保存数据,数组的容量可以动态增长。LinkedList是基于双向链表实现的,它的内部使用链表保存数据。由于两种数据结构的不同,在性能、内存消耗和使用场景上有一些区别。
首先,ArrayList的读取和修改元素的速度较快,因为它能够根据索引直接访问元素。而LinkedList的插入和删除元素的速度较快,因为它只需要改变前后节点的指向即可。
其次,ArrayList的内存消耗较小,因为它只需要存储元素本身以及一些额外的元数据,而LinkedList需要额外的存储指针来维护链表结构。
扩容机制
ArrayList的扩容机制是在数组元素不足以容纳新元素时,会创建一个新的更大的数组,并将原数组中的元素复制到新数组中。默认情况下,每次扩容都会将数组的容量增加50%。
private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }
LinkedList的扩容机制是在插入元素时不需要额外的扩容操作,因为链表的容量是动态的。每次插入新元素时,只需要创建一个新的节点,并将其添加到链表中即可。
底层实现方式
ArrayList的底层使用数组来保存元素,定义了一个Object类型的数组变量elementData来存放元素,可以通过索引直接访问数组中的元素。ArrayList还提供了一些方法(如add、remove等)来方便地操作数组。在插入或删除元素时,需要移动数组中的部分元素。
private Object[] elementData; public E get(int index) { rangeCheck(index); return elementData(index); }
LinkedList的底层使用双向链表来保存元素,定义了一个Node节点类作为链表的节点类型。每个节点包含前向指针prev、后向指针next和存储的元素值。LinkedList通过头节点和尾节点来维护链表的头尾。在插入或删除元素时,只需要改变节点的指针即可。LinkedList还提供了一些方法(如add、remove等)来方便地操作链表。
private static class Node{ E item; Node next; Node prev; Node(Node prev, E element, Node next) { this.item = element; this.next = next; this.prev = prev; } }
总结
ArrayList和LinkedList都是常用的Java集合类,各自适用于不同的场景。ArrayList适合读取和修改元素的操作,LinkedList适合插入和删除元素的操作。ArrayList底层使用数组保存数据,在数据量较大时可以减少内存消耗,但在插入和删除元素时性能较差。LinkedList底层使用链表保存数据,在插入和删除元素时性能较好,但在读取和修改元素时性能较差。根据具体的应用场景和需求,选择合适的集合类可以提高程序的性能和效率。