一、概述
一种可以动态增长和缩减的索引序列
直接父类是AbstractList
实现了4个接口:List, RandomAccess(标记接口,表明支持快速随机访问元素), Cloneable, java.io.Serializable
二、特点
1. 可动态增长和缩减容量
2. 内部使用Object数组存放数据
3. 内部数组的初始容量是10,放满后以1.5倍容量增长
4. 可通过索引快速随机访问元素
三、容量
涉及初始容量、最大容量、容量增长速度,容量如何增长
- 初始容量 = 10
- 最大容量 = (Integer.MAX_VALUE - 8)
最大可分配的数组大小,最大值为如果向虚拟机请求分配的内存超过了虚拟机内存限制,就会抛出内存溢出错误 - 容量以1.5倍速度增长
ArrayList中定义了两个扩充(或判断)数组容量的方法:
一给外界使用(ensureCapacity方法),
一个用于内部(ensureCapacityInternal方法),
两者都调用了ensureExplicitCapacity方法 - 扩充容量,使用的Arrays.copyOf(Object[] original, int newLength)方法,该方法在底层还是使用了System.copyof方法进行拷贝
四、三个构造函数
无参构造、带有初始容量的构造、带有初始化集合的构造
下面的构造函数中的参数是初始容量,并不是指定数组中元素个数
五、如何添加元素的
添加元素必须要检查容量
- public boolean add(E e)
将元素添加到数组的末尾
首先,判断是否可以容纳(size+1)个元素,如果不能容纳,进行扩容
然后,将元素放在size索引位置,并修改数组大小
最后,添加成功返回true - public void add(int index, E element)
首先,检查索引(当索引<0或索引>size()将抛出IndexOutOfBoundsException异常)
接着,判断是否可以容纳(size+1)个元素,如果不能容纳,进行扩容
然后,使用System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)对index索引之后的元素进行移位
移位后,将数据放在index索引处,并调整数组大小
六、如何删除元素的
有两种删除元素的方法:remove(int index) 和 remove(Object o)
在使用时,需要注意以下问题:
- 集合元素是Integer时,尝试删除元素,可能会抛出IndexOutOfBoundException异常
当集合中元素类型是整数时,编译器不会对要删除的整数进行自动装箱,会把要删除的整数当成索引,从而调用remove(int index)方法,当这个整数超过了索引最大值,从而抛出IndexOutOfBoundException异常,解决办法:手动自动装箱
List<Integer> list = Arrays.asList(999, 222, 444, 999);
// 抛出IndexOutOfBoundException异常
// 因为此时编译器不会对999进行自动装箱,会把999当成索引,从而调用remove(int index)方法
// 解决办法:手动自动装箱
// list.remove(999);
list.remove(Integer.valueOf(999));
System.out.println(list); // OK, The result is [222, 444, 999]
- 在迭代元素的时候,使用list.remove()方法删除元素会抛出ConcurrentModificationException异常,
解决办法:
- 使用iterator.remove()方法删除
- 使用CopyOnWriteArrayList列表
private static void testRemove02() {
System.out.println("\n删除元素: ");
ArrayList<Integer> list = new ArrayList<>();
list.add(999);
list.add(222);
list.add(333);
list.add(999);
for (Iterator<Integer> iterator = list.iterator(); iterator.hasNext();) {
Integer value = iterator.next();
// list.remove(value);
iterator.remove();
System.out.println(list);
}
list = new ArrayList<>();
list.add(999);
list.add(222);
list.add(333);
list.add(999);
// 同样会抛出ConcurrentModificationException异常
for (Integer value: list) {
// list.remove(value);
}
}
- 如果没有调用next方法就执行remove()操作,将会抛出IllegalStateException异常
private static void testRemove03() {
System.out.println("\n删除元素: ");
ArrayList<Integer> list = new ArrayList<>();
list.add(999);
list.add(222);
list.add(333);
list.add(999);
for (Iterator<Integer> iterator = list.iterator(); iterator.hasNext();) {
// 抛出IllegalStateException异常
// iterator.remove();
}
}
因为迭代器的工作原理如下图所示:
七、是怎样取列表子集的
给外界提供的方法是:public List subList(int fromIndex, int toIndex)
获取的元素范围(前闭后开区间)为:[fromIndex, toIndex)
首先,检查索引是否满足要求(fromIndex不能小于0,toIndex不能大于数组size,fromIndex不能大于toIndex)
然后,通过构建内部类SubList的实例来获取指定范围内的元素列表