概述
ArrayList是Java中使用率很高的集合容器,面试频率也很高,本篇文章主要对ArrayList这个容器从功能到源码做一个深入解析,使用的是jdk8来讲解。
功能介绍
ArrayList是一个有顺序的容器,底层是一个数组,不过它是会进行动态扩容。
特点:
- 是有顺序的容器, 底层是数组,会进行自动扩容,动态增大数组的长度
- 允许放入null元素
- 不是线程安全,并发修改的时候会抛出ConcurrentModificationException异常
构造方法
- ArrayList()
说明:构造一个空容器,底层的数组长度默认为10
- ArrayList(int initialCapacity)
说明:构造一个初始长度为initialCapacity大小的容器,也就是底层的数组长度为initialCapacity
- ArrayList(Collection<? extends E> c)
说明:构造一个内容为入参容器c的有序的容器。
新增元素相关方法
- boolean add(E e)
说明: 向集合中添加元素
- void add(int index, E element)
说明: 向集合指定位置后面添加一个元素
- boolean addAll(Collection<? extends E> c)
说明: 向集合中添加另外一个集合的元素
- boolean addAll(int index, Collection<? extends E> c)
说明: 向集合指定位置后面添加另外一个集合的全部元素
修改元素相关方法
E set(int index, E element)
说明: 设置集合中某个位置元素的值,返回修改前的内容
删除元素相关方法
boolean remove(Object o)
说明:删除集合中碰到的第一和o一样的元素,如果集合发生变化返回true
E remove(int index)
说明:删除集合中某个位置的元素,返回删除的元素内容
boolean removeAll(Collection<?> c)
说明:根据入参的集合,删除集合里面一样的元素,如果集合发生变化,返回true
void clear()
说明:清空集合中的元素
查找相关方法
- int size()
说明:返回容器中元素的数量
- boolean isEmpty()
说明:返回容器是否是空的,如果是空,返回true
- boolean contains(Object o)
说明:返回容器是否包含指定对象
- boolean containsAll(Collection<?> c)
说明:返回容器是否包含全部的对象
- E get(int index)
说明:获取指定索引位置的元素
- int indexOf(Object o)
说明:从头部开始找,获取查找到指定元素的第一个索引位置, 如果返回-1表示没有找到
- int lastIndexOf(Object o)
说明:从后面往前找,获取查找到指定元素的第一个索引位置,如果返回-1表示没有找到
- Object[] toArray()
说明:容器转换成数组
- T[] toArray(T[] a)
说明:容器转换成指定类型的数组
- Iterator iterator()
说明:返回容器的迭代器,用于遍历容器
- ListIterator listIterator()
说明:返回容器的列表迭代器,继承自Iterator,可以往前查
- ListIterator listIterator(int index)
说明:返回容器的列表迭代器,继承自Iterator,可以往前查
- List subList(int fromIndex, int toIndex)
说明:返回容器指定位置开始的列表迭代器
- boolean equals(Object o)
说明:容器中的每个元素都必须equals
- int hashCode()
说明:容器中每个元素的hashCode相加
JDK8新增方法
- void replaceAll(UnaryOperator operator)
说明:根据传入的函数逻辑替换容器中的每个元素
- void sort(Comparator<? super E> c)
说明:根据传入的排序器排序容器中的元素
- Spliterator spliterator()
说明:返回与 ArrayList 相同元素的 Spliterator,支持并发的遍历和分拆数据元素。
使用案例
public class ArrayListTest { public static void main(String[] args) { // 创建容器,最好传入容器预估的大小 List<String> usernames = new ArrayList<>(16); // 添加元素 usernames.add("alvin"); usernames.add("cxw"); usernames.add("kk"); usernames.add("alvin"); usernames.add("lucy"); usernames.add("cc"); usernames.add("alvin"); // 修改元素 usernames.set(5, "tt"); //查看元素 System.out.println(usernames.get(5)); // 删除元素 usernames.remove("alvin"); // cxw, kk, alvin, lucy, tt, alvin System.out.println(usernames); List<String> deleteUserNames = new ArrayList<>(1); deleteUserNames.add("alvin"); // [cxw, kk, lucy, tt] usernames.removeAll(deleteUserNames); System.out.println(usernames); // 遍历删除的正确姿势 Iterator<String> iterator = usernames.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if ("alvin".equals(item)) { iterator.remove(); } } //使用Lambda表达式使用每个字符的长度替代原集合的元素 usernames.replaceAll(ele -> ele + " NB"); System.out.println(usernames); // 并发遍历,具体去学习下分割器 usernames.spliterator().forEachRemaining(item -> System.out.println(item)); } }
使用注意事项
- ArrayList的元素支持null, 所以有时候对数据的判空处理是必不可少的。
- ArrayList 的 subList 结果不可强转成 ArrayList,否则会抛出 ClassCastException 异常,
java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。
说明:subList() 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList 本身,而是 ArrayList 的一个视图,对于SubList 的所有操作最终会反映到原列表上。
- 在 subList 场景中,高度注意对父集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生 ConcurrentModificationException 异常。
说明:抽查表明,90% 的程序员对此知识点都有错误的认知。
- 使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一致、长度为0 的空数组。
- 使用 Collection 接口任何实现类的 addAll() 方法时,要对输入的集合参数进行 NPE 判断。 说明:在 ArrayList#addAll 方法的第一行代码即 Object[] a = c.toArray();其中 c 为输入集合参数,如果为 null,则直接抛出异常。
- 不要在 foreach 循环里进行元素的 remove / add 操作。remove 元素请使用 iterator 方式,如果并发操作,需要对 iterator 对象加锁。
- 使用工具类 Arrays.asList() 把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/ remove / clear 方法会抛出 UnsupportedOperationException 异常。
- Collections 类返回的对象,如:emptyList() / singletonList() 等都是 immutable list,不可对其进行添加或者删除元素的操作。