使用迭代遍历集合过程中修改集合引发的异常分析和addFirst方法原理分析

1.集合的3种基本遍历

public class Hello03 {
    public static void main(String[] args) {
        List list=new ArrayList();
        list.add("hello");
        list.add("world");
        System.out.println(list);
        //适用于有下标的有序集合
        for (int i = 0; i <list.size() ; i++) {
            System.out.println(list.get(i));
        }
        //增强for和迭代器原理一致的,适用于所有的集合,
        for (Object objs:list){
            System.out.println(objs);
        }
        Iterator it =list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }
}

2.普通for循环遍历集合的时候向集合中加数据不会报错
在这里插入图片描述
3.增强for循环和迭代器遍历集合的时候向集合中填加数据会报错***
在这里插入图片描述

在这里插入图片描述
4.增强for循环和迭代器遍历集合的时候向集合中修改数据没有报错
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.addFirst方法原理分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<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、付费专栏及课程。

余额充值