Java 集合-List
本文将介绍 Java 集合中的 List。
一、什么是 List?
List,列表,用于储存一组可重复的、有序的对象。
二、常用方法
1. Collection 方法
2. 特有方法
方法 | 说明 |
---|---|
add(index, obj) | 将元素插入到 index 处 |
addAll(index, collection) | 将集合中所有元素插入到 index 处 |
get(index) | 返回 index 处的元素 |
indexOf(obj) | 返回元素在集合中第一次出现的位置 |
lastIndexOf(obj) | 返回元素在集合中最后一次出现的位置 |
remove(index) | 删除并返回 index 处的元素 |
set(index, obj) | 将 index 处的元素替换为指定元素 |
subList(fromIndex, toIndex) | 返回从 fromIndex 到 toIndex 的所有元素组成的子集 |
replaceAll(UnaryOperator operator) | 根据 operator 指定的计算规则重新设置集合中所有的元素 |
sort(Comparator comparator) | 根据 comparator 对集合中元素进行排序 |
3. 迭代器特有方法
方法 | 说明 |
---|---|
hasPrevious() | 是否有上一个元素 |
previous() | 返回上一个元素 |
add(obj) | 插入元素 |
三、fail-fast 迭代
在使用迭代器迭代的过程中,如果对集合进行了修改,将导致迭代结果不正确。
例如在迭代过程中删除集合元素:
1
2
3
4
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
arrayList.remove(0);
}针对这一问题,AbstractList 提供了可选的 fail-fast 迭代方案,具体如下:
- 在对象中维护一个成员属性 modCount
- 假如对 List 进行修改,应该递增 modCount 值
- 迭代器将会在迭代过程中检测 modCount 值,并在其异常改变后抛出错误
网上的一部分说法存在误区,fail-fast 迭代的目的不是解决多线程访问问题,而是为了解决单一线程在迭代过程中修改的问题。
在 JDK5、JDK6 中,modCount 有 volatile 修饰,但自 JDK7 以来,modCount 已不再添加 volatile 修饰符。因此,fail-fast 迭代不是为了解决多线程访问问题,并且也没有能力解决它。
四、ArrayList
1. 特点
底层通过数组实现
与普通数组相比,没有容量限制
当容量不足时,会自动扩大数组大小
与普通数组相比,只能存储对象
2. initialCapacity
initialCapacity 表示初始容量。
可以通过构造函数指定,如果没有指定,则初始容量默认为 10。
一般情况下无需关心此参数,随着元素的添加,ArrayList 会自动扩容。
3. 自动扩容
每次添加元素前,检查容量是否充足,在容量不足时扩容。
1 |
|
4. 手动扩容
ArrayList 提供了 ensureCapacity 方法,可以用它来手动扩容。
如果可以预知 list 的元素增加情况,应该手动将容量扩到合适大小,以避免元素添加过程中由 ArrayList 自行多次扩容而导致的性能损耗。
5. 手动缩容
可以通过 trimToSize 调整容量为当前元素个数,以减少空间占用。
6. fail-fast 迭代
ArrayList 支持 fail-fast 迭代机制。
五、LinkedList
1. 特点
- 底层通过链表实现
- 同时实现了 List、Deque 接口,因此既可以作为列表,又可以作为队列
参考
疯狂 Java 讲义