概述
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, alvinSystem.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,不可对其进行添加或者删除元素的操作。
参考
pdai.tech/md/java/col…
www.infoq.cn/article/9av…
www.cnblogs.com/tong-yuan/p…