一、概述

一种可以动态增长和缩减索引序列

直接父类是AbstractList
实现了4个接口:List, RandomAccess(标记接口,表明支持快速随机访问元素), Cloneable, java.io.Serializable

二、特点

1. 可动态增长和缩减容量
2. 内部使用Object数组存放数据
3. 内部数组的初始容量是10,放满后以1.5倍容量增长
4. 可通过索引快速随机访问元素

三、容量

涉及初始容量、最大容量、容量增长速度,容量如何增长

  • 初始容量 = 10
  • java arrayList属性 最大值的索引 stream_java

  • 最大容量 = (Integer.MAX_VALUE - 8)
    最大可分配的数组大小,最大值为java arrayList属性 最大值的索引 stream_java_02如果向虚拟机请求分配的内存超过了虚拟机内存限制,就会抛出内存溢出错误
  • 容量以1.5倍速度增长
    ArrayList中定义了两个扩充(或判断)数组容量的方法:
    一给外界使用(ensureCapacity方法),
    一个用于内部(ensureCapacityInternal方法),
    两者都调用了ensureExplicitCapacity方法
  • java arrayList属性 最大值的索引 stream_java_03


  • java arrayList属性 最大值的索引 stream_数组_04


  • java arrayList属性 最大值的索引 stream_集合_05

  • 扩充容量,使用的Arrays.copyOf(Object[] original, int newLength)方法,该方法在底层还是使用了System.copyof方法进行拷贝
  • java arrayList属性 最大值的索引 stream_数组_06

四、三个构造函数

无参构造、带有初始容量的构造、带有初始化集合的构造

java arrayList属性 最大值的索引 stream_ArrayList_07

下面的构造函数中的参数是初始容量,并不是指定数组中元素个数

java arrayList属性 最大值的索引 stream_java_08


java arrayList属性 最大值的索引 stream_ArrayList_09

五、如何添加元素的

添加元素必须要检查容量

  • public boolean add(E e)
    将元素添加到数组的末尾
    首先,判断是否可以容纳(size+1)个元素,如果不能容纳,进行扩容
    然后,将元素放在size索引位置,并修改数组大小
    最后,添加成功返回true
  • java arrayList属性 最大值的索引 stream_集合_10

  • 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索引处,并调整数组大小
  • java arrayList属性 最大值的索引 stream_ArrayList_11

六、如何删除元素的

有两种删除元素的方法: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异常
    解决办法:
  1. 使用iterator.remove()方法删除
  2. 使用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();
   }
}

因为迭代器的工作原理如下图所示:

java arrayList属性 最大值的索引 stream_ArrayList_12

七、是怎样取列表子集的

给外界提供的方法是:public List subList(int fromIndex, int toIndex)
获取的元素范围(前闭后开区间)为:[fromIndex, toIndex)

首先,检查索引是否满足要求(fromIndex不能小于0,toIndex不能大于数组size,fromIndex不能大于toIndex)
然后,通过构建内部类SubList的实例来获取指定范围内的元素列表

java arrayList属性 最大值的索引 stream_集合_13