ArrayList和LinkList 复习

ArrayList底层是由数组实现的,而正是因为数组的特性,ArrayList支持随机访问,实现了RandomAccess()接口,可借用get()方法通过数组下标实现随机访问得到元素。

LinkList底层是由双向链表实现的,双向链表一次只能寻找到他的前驱和后继元素,所以不支持随机访问,未能实现RandomAccess()接口,虽然LinkList也可以通过向get()方法传入下标访问,不过在LinkList的get()方法里实现的是一个node()方法。它是通过对比下标的大小是否大于或小于链表长度的一半,然后从头或者从尾进行遍历得到。node()方法如下。

Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

 

 对ArrayList的增加和删除操作,若是在数组表尾删除和添加,可直接更改数组大小即可。若在其他位置删除,则需将删除位置之后的元素向前移动,若在其他位置添加,则需在添加位置向后移动。

对LinkList的添加和删除操作。删除与添加只需要更改删除元素或添加位置前驱和后继的next与prev即可。

所以对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。

 

同时ArrayLIst默认大小为10,在对其进行添加时,若超出了数组的大小,就会发生动态扩容,扩容大小为原来的1.5倍。

   private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

 

 

<think>好的,用户想了解Java中ArrayListLinkedList的底层实现区别、数据结构源码解析。首先,我需要回忆一下两者的基本概念结构。 ArrayList是基于数组实现的,动态数组,会自动扩容。记得它的构造方法有几个,比如默认构造方法会创建一个空数组,添加元素时才扩容到默认容量10。而LinkedList是双向链表,每个节点有前后指针,插入删除效率高,但随机访问慢。 接下来需要对比两者的数据结构。数组链表的结构差异明显,数组在内存中连续,链表通过指针连接。因此,ArrayList随机访问时更快,而LinkedList在插入删除时更有优势。 然后要分析源码部分。对于ArrayList,扩容机制是关键,当元素数量超过数组长度时,会增长到原来的1.5倍,使用Arrays.copyOf()。而LinkedList的添加删除操作主要是调整节点的前后引用,不需要扩容,但每个元素需要额外的空间存储指针。 另外,需要提到两者的继承结构实现的接口。比如ArrayList继承自AbstractList,而LinkedList还实现了Deque,可以当作队列使用。这也是区别之一,用户可能需要注意这些方法的不同。 还要考虑线程安全的问题,两者都不是线程安全的,如果在多线程环境下使用需要外部同步。这可能涉及到快速失败机制,迭代时的并发修改会抛出异常,引用中的场景提到了这一点。 用户可能的应用场景也需要考虑,比如频繁查询用ArrayList,频繁增删用LinkedList。不过实际中,可能还要考虑内存性能的平衡,比如ArrayList扩容时的开销,LinkedList每个节点的额外内存占用。 最后,根据引用内容,需要确保回答中包含源码分析,比如ArrayList的grow方法,LinkedList的节点结构。同时要比较它们的性能差异,时间复杂度,以及使用时的选择建议。 可能还需要检查是否有遗漏的点,比如初始容量、内存占用、迭代器实现等。比如ArrayList的迭代器是快速失败的,而LinkedList的迭代器可能也有类似机制,但具体实现可能不同。 总结下来,回答的结构应该是先介绍各自的数据结构,再分析源码关键部分,对比区别,最后给出应用场景建议。这样用户能逐步理解两者的不同,并根据需求选择合适的集合类。</think>### ArrayList与LinkedList底层实现原理分析 #### 一、数据结构差异 1. **ArrayList** - 基于**动态数组**实现,内部使用`Object[] elementData`存储数据 - 默认初始容量为10,扩容时按照原容量的1.5倍增长 - 内存连续分配,支持快速随机访问(时间复杂度$O(1)$) - 源码中扩容逻辑: ```java private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容 elementData = Arrays.copyOf(elementData, newCapacity); } ```[^3] 2. **LinkedList** - 基于**双向链表**实现,节点定义: ```java private static class Node<E> { E item; Node<E> next; Node<E> prev; } ``` - 无需预先分配内存空间,每个元素包含前后节点指针 - 插入/删除时间复杂度$O(1)$,但随机访问需要遍历链表(时间复杂度$O(n)$)[^2] #### 二、核心操作对比 | 操作类型 | ArrayList | LinkedList | |----------------|----------------------------|---------------------------| | 随机访问(get) | $O(1)$ | $O(n)$ | | 头部插入 | $O(n)$(需要移动元素) | $O(1)$ | | 中间插入 | $O(n)$ | $O(n)$(需先定位节点) | | 尾部插入 | $O(1)$(无扩容时) | $O(1)$ | | 内存占用 | 仅存储元素 | 额外存储两个指针 | #### 三、源码关键实现 1. **ArrayList扩容机制** - 首次添加元素时初始化为10容量 - 每次add操作前检查容量: ```java public boolean add(E e) { ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } ``` - 扩容时调用`Arrays.copyOf()`进行数组复制 2. **LinkedList操作优化** - 插入操作直接修改节点指针: ```java void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; } ``` - 实现`Deque`接口提供队列操作`addFirst()`/`addLast()`[^5] #### 四、应用场景建议 1. **优先选择ArrayList** - 需要频繁随机访问元素 - 数据量变化较小,尾部插入为主 - 内存敏感场景(每个元素节省24字节指针空间) 2. **优先选择LinkedList** - 频繁在头部/中部插入删除 - 需要实现队列/双端队列功能 - 数据总量波动较大且无法预估规模[^1] #### 五、注意事项 - 两者都是**非线程安全**集合,多线程环境下需使用`Collections.synchronizedList()`包装[^4] - 迭代过程中修改集合会触发`ConcurrentModificationException`(快速失败机制) - LinkedList的`ListIterator`迭代器支持双向遍历
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值