概述

ArrayList是Java中使用率很高的集合容器,面试频率也很高,本篇文章主要对ArrayList这个容器从功能到源码做一个深入解析,使用的是jdk8来讲解。

功能介绍

ArrayList是一个有顺序的容器,底层是一个数组,不过它是会进行动态扩容。

特点:

  • 是有顺序的容器, 底层是数组,会进行自动扩容,动态增大数组的长度
  • 允许放入null元素
  • 不是线程安全,并发修改的时候会抛出ConcurrentModificationException异常

构造方法

  1. ArrayList()

说明:构造一个空容器,底层的数组长度默认为10

  1. ArrayList(int initialCapacity)

说明:构造一个初始长度为initialCapacity大小的容器,也就是底层的数组长度为initialCapacity

  1. ArrayList(Collection<? extends E> c)

说明:构造一个内容为入参容器c的有序的容器。

新增元素相关方法

  1. boolean add(E e)

说明: 向集合中添加元素

  1. void add(int index, E element)

说明: 向集合指定位置后面添加一个元素

  1. boolean addAll(Collection<? extends E> c)

说明: 向集合中添加另外一个集合的元素

  1. boolean addAll(int index, Collection<? extends E> c)

说明: 向集合指定位置后面添加另外一个集合的全部元素

修改元素相关方法

  1. E set(int index, E element)

说明: 设置集合中某个位置元素的值,返回修改前的内容

删除元素相关方法

  1. boolean remove(Object o)

说明:删除集合中碰到的第一和o一样的元素,如果集合发生变化返回true

  1. E remove(int index)

说明:删除集合中某个位置的元素,返回删除的元素内容

  1. boolean removeAll(Collection<?> c)

说明:根据入参的集合,删除集合里面一样的元素,如果集合发生变化,返回true

  1. void clear()

说明:清空集合中的元素

查找相关方法

  1. int size()

说明:返回容器中元素的数量

  1. boolean isEmpty()

说明:返回容器是否是空的,如果是空,返回true

  1. boolean contains(Object o)

说明:返回容器是否包含指定对象

  1. boolean containsAll(Collection<?> c)

说明:返回容器是否包含全部的对象

  1. E get(int index)

说明:获取指定索引位置的元素

  1. int indexOf(Object o)

说明:从头部开始找,获取查找到指定元素的第一个索引位置, 如果返回-1表示没有找到

  1. int lastIndexOf(Object o)

说明:从后面往前找,获取查找到指定元素的第一个索引位置,如果返回-1表示没有找到

  1. Object[] toArray()

说明:容器转换成数组

  1. T[] toArray(T[] a)

说明:容器转换成指定类型的数组

  1. Iterator iterator()

说明:返回容器的迭代器,用于遍历容器

  1. ListIterator listIterator()

说明:返回容器的列表迭代器,继承自Iterator,可以往前查

  1. ListIterator listIterator(int index)

说明:返回容器的列表迭代器,继承自Iterator,可以往前查

  1. List subList(int fromIndex, int toIndex)

说明:返回容器指定位置开始的列表迭代器

  1. boolean equals(Object o)

说明:容器中的每个元素都必须equals

  1. int hashCode()

说明:容器中每个元素的hashCode相加

JDK8新增方法

  1. void replaceAll(UnaryOperator operator)

说明:根据传入的函数逻辑替换容器中的每个元素

  1. void sort(Comparator<? super E> c)

说明:根据传入的排序器排序容器中的元素

  1. 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));
        }
    }

使用注意事项

  1. ArrayList的元素支持null, 所以有时候对数据的判空处理是必不可少的。
  2. ArrayList 的 subList 结果不可强转成 ArrayList,否则会抛出 ClassCastException 异常,java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。

说明:subList() 返回的是 ArrayList 的内部类 SubList,并不是 ArrayList 本身,而是 ArrayList 的一个视图,对于SubList 的所有操作最终会反映到原列表上。

  1. 在 subList 场景中,高度注意对父集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生 ConcurrentModificationException 异常。

说明:抽查表明,90% 的程序员对此知识点都有错误的认知。

  1. 使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一致、长度为0 的空数组。
  2. 使用 Collection 接口任何实现类的 addAll() 方法时,要对输入的集合参数进行 NPE 判断。 说明:在 ArrayList#addAll 方法的第一行代码即 Object[] a = c.toArray();其中 c 为输入集合参数,如果为 null,则直接抛出异常。
  3. 不要在 foreach 循环里进行元素的 remove / add 操作。remove 元素请使用 iterator 方式,如果并发操作,需要对 iterator 对象加锁。
  4. 使用工具类 Arrays.asList() 把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/ remove / clear 方法会抛出 UnsupportedOperationException 异常。
  5. Collections 类返回的对象,如:emptyList() / singletonList() 等都是 immutable list,不可对其进行添加或者删除元素的操作。

参考

pdai.tech/md/java/col…

www.infoq.cn/article/9av…

www.cnblogs.com/tong-yuan/p…

https://juejin.cn/extension/?utm_source=standalone&utm_medium=post&utm_campaign=extension_promotion)

最后修改:2022 年 09 月 04 日
如果觉得我的文章对你有用,请随意赞赏