Java列表和队列用法与原理剖析(1.ArrayLIst)

本文详细介绍了Java中ArrayList的用法、内部原理和迭代机制,包括其动态数组的实现方式、增删改查操作,以及在迭代过程中如何避免`ConcurrentModificationException`。此外,还讨论了ArrayList的性能特点,如随机访问的高效性和插入删除的相对低效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文是阅读《Java编程的逻辑》进行的学习笔记总结,如有错误望各位指正

ArrayList

用法

ArrayList是一个动态数组泛型容器,新建ArrayList需要实例化泛型参数,如:

ArrayList<String> al = new ArrayList<String>();

同时写有增删改查的各种方法,在这里就不一一解释了

原理

ArrayList内部有一个数组elementData和一个整数size,ArrayList的各种public方法内部操作都是基于这个数组和这个整数,elementData会随着实际元素个数的增多而重新分配,而size始终记录实际元素的个数,要注意的是,类似于add,remove这些方法都会用modCount来记录内部的修改次数,要记录修改次数的原因,下面的[迭代的陷阱中]解释

迭代

ArrayList实现了Iterable接口,所以支持foreach语法。
Iterable接口里面实现了iterator()方法,iterator()方法返回的是一个Iterator对象,实际就是使用Iterator接口的方法进行遍历。也就是说

  • 对象只要实现了Iterable,就可以使用foreach
  • 类可以不用实现Iterable,也能创建Iterator对象

迭代的陷阱(小心,也是用foreach删除元素报错的原因)

如果想用迭代的方式删除小于100的元素,直觉上可以这么写

public void remove(ArrayList<Integer>list){
	for(Integer a:list){
		if(a<=100){
			list.remove(a);
		}	
	}
}

但运行时会抛出异常:ConcurrentModificationException并发修改异常,这是因为迭代器内部会维护一些索引位置相关的数据,要求在迭代过程中,容器不能发生结构性变化,否则这些索引位置就失效了。所谓结构性变化就是添加,插入,删除操作,修改内容不算结构性变化。而之前所说的modCount记录内部修改次数就是为了迭代器判断是否发生结构性变化设置的。
如果想要避免异常,可以使用迭代器的remove方法,如下:

public static void remove(ArrayList<Integer> list){
	Iterator<Integer> it = list.iterator();
	while(it.hasNext()){
		if(it.next<100){
			it.remove();
		}
	}
}

迭代器是如何知道发生了结构性变化的呢?

ArrayList中iterator方法,会新建一个实现了Iterator接口的Itr对象,这个对象内部有三个int类型的成员变量cursor(表示下一个要返回元素的位置),lastRet(表示最后一个返回的索引位置,没有则为-1),expectedModCount(表示期望的修改次数,初始化为modCount),上一节也说过,modCount是用来记录内部修改次数的,而每次迭代器操作的时候都会检查expectedModCount是否等于modCount,这样就可以检测出结构性变化。
而迭代器的remove方法能够成功,是因为它remove的同时更新了cursor、lastRet、expectedModCount的值,所以可以正确删除,在这就不具体说明,详情可看其源码。

ArrayList实现的主要接口

  1. Collection
    Collection表示一个数据的集合,数据间没有位置或顺序的概念
  2. List
    List表示有顺序或位置的数据集合,它扩展了Collection。增加了一些关于位置的方法
  3. RandomAccess
    这个接口没有定义任何代码,这种称为标记接口,用于声明类的一种属性
    实现了RandomAccess接口的类表示可以随机访问,随机访问的意思是类似于数组那样,数据在内存中是连续存放的,根据索引值就可以直接定位到具体的元素,访问效率很高,你可以随机访问任一个节点,而不需要通过当前节点查找后续节点,遍历访问模式请参考LinkedList的结构。
小tips:ArrayList打印顺序会与添加顺序一致

ArrayList使用线性顺序存储结构,和数组一致,每个对象有一个index,index本身是有序的,所以你添加的时候,index有序增长,遍历的时候,按照index遍历,也是有序的。存放和访问顺序可能不一致,那需要在存放的时候就是随机存放的,比如HashMap,数据通过hash计算后无序存放,所以获取的时候也是随机的,需要存放和读取顺序一致,就要包装一层LinkedList,也就是LinkedHashMap

ArrayList特点分析

ArrayList特点是内部采用动态数组实现,有以下特点

  1. 可以随机访问,按照索引位置访问效率很高,O(1)
  2. 按照内容查找元素效率较低,O(N)
  3. 添加元素效率一般,重新分配和复制数组的开销被平摊了,O(N)
  4. 插入和删除元素效率较低,因为需要移动元素,O(N)
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值