ArrayList源码总结(JDK1.8)

ArrayList源码总结基于jdk_8,如有错误欢迎指正

1. 类的继承关系

ArrayList类继承自AbstractList类,实现了List接口
在这里插入图片描述


2. 变量及其含义

变量名修饰符类型默认值含义
serialVersionUIDprivate static finallong8683452581122892189L利用该值验证序列化版本的一致性
DEFAULT_CAPACITYprivate static finalint10初始化的ArrayList大小
EMPTY_ELEMENTDATAprivate static finalObject[]{}有参构造,但传入的initialCapacity为0时,elementData默认值
DEFAULTCAPACITY_EMPTY_ELEMENTDATAprivate static finalObject[]{}无参构造elementData默认值
elementDatatransientObject[]存储ArrayList内容的缓冲区数组ArrayList的本质就是在维护一个Object数组
sizeprivateintArrayList的长度
MAX_ARRAY_SIZEprivate static finalintInteger.MAX_VALUE - 8ArrayList的最大容量
------------------------------
modCount(父类AbstractList中的全局变量)protected transientint0记录list大小改变的次数

3. 构造函数

3.1. 有参构造

1. 变量初始化方式

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
  • 有参构造流程
    在这里插入图片描述
    2. 集合初始化方式
   public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
  • 指定初始数据初始化时,会有这样的注释“ see 6260652”,这是 Java 的一个 bug,意思是当给定集合内的元素不是
    Object 类型时,会转化成 Object 的类型。一般情况下都不会触发此 bug,只有在下列场景下才会触发:ArrayList
    初始化之后(ArrayList 元素非 Object 类型),再次调用 toArray 方法,得到 Object 数组,并且往
    Object 数组赋值时,才会触发此 bug。代码和原因如下图:
    在这里插入图片描述
    该bug是由于向上转型造成的,在jdk1.9中被解决

  • 集合初始化方式流程
    在这里插入图片描述

利用该构造函数初始化数组举例

//第一种,利用Array.asList()初始化
ArrayList arrayList1 = new ArrayList<>(Arrays.asList("arrayList","arrayList","arrayList"));
System.out.println(arrayList1);

//第二种,利用Collection.nCopies()初始化
ArrayList<String> arrayList2 = new ArrayList<>(Collections.nCopies(3, "arrayList"));
System.out.println(arrayList2);

输出都是:[arrayList, arrayList, arrayList]

3.2. 无参构造

    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  • tips:无参构造最开始也被初始化为空,只有在首次插入元素扩容时才会将数组大小扩充为10

4. 成员方法

名称修饰符返回值类型参数参数释义返回值返回值释义功能
trimToSize()publicvoid将ArrayList调整为列表当前大小,可以使用该操作最小化ArrayList实例的存储
ensureCapacity()publicvoidminCapacity期望的最小容量预设ArrayList的大小,以提高初始化速度
ensureCapacityInternal()privatevoidminCapacity期望的最小容量ArrayList扩容时调用该方法
ensureExplicitCapacity()privatevoidminCapacity期望的最小容量确保ArrayList扩容所需的最小容量能被分配
grow()privatevoidminCapacity期望的最小容量增加容量,以确保它至少可以容纳minimum capacity参数指定的元素数
hugeCapacity()privatestatic intminCapacity期望的最小容量防止ArrayList容量溢出
size()publicintsizeArrayList的长度获取当前ArrayList的长度
isEmpty()publicbooleantrue/false返回ArrayList是否为空判断ArrayList是否为空
contains()publicbooleanObject o要测试的是否在ArrayList中存在的元素true/false元素是否存在判断ArrayList中是否存在某一元素
indexOf()publicintObject o希望在ArrayList中找到的元素[-1,Integer.MAX_Value]元素是否存在顺序查找并返回某一元素在ArrayList中的位置
lastIndexOf()publicintObject o希望在ArrayList中找到的元素[-1,Integer.MAX_Value]元素是否存在逆序查找并返回某一元素在ArrayList中的位置
clone()publicObjectObjectObject对象数组ArrayList浅拷贝
toArray()publicObject[]Object[]Object对象数组将List转换为数组
toArray()public T[]T[] a T[]Object对象数组将List转换为数组(泛型)
get()publicEint index索引Eindex对应的数组元素获取ArrayList指定位置的元素
set()publicE(int index, E element)索引E更新之前index对应的元素(旧值)将ArrayList指定位置的元素替换为指定元素
add()publicboolean(E e)元素true/false元素是否追加成功在ArrayList末尾追加一个元素
add()publicvoid(int index, E element)(要插入的位置, 要插入的元素)在指定位置插入一个元素(重载)
remove()publicEint index索引E删除之前index对应的元素(旧值)将ArrayList指定位置的元素删除
fastRemove()privatevoidint index索引通过arraycopy方法对ArrayList内的元素进行前移
clear()publicvoidArrayList长度为0,并清空ArrayList中的所有元素
addAll()publicboolean(Collection<? extends E> c)要添加的集合元素true/false集合是否添加成功ArrayList后追加一个集合
addAll()publicboolean(int index, Collection<? extends E> c)要添加的集合元素及索引true/false集合是否添加成功ArrayList的指定位置追加一个集合(重载)
removeRange()protectedvoid(int fromIndex, int toIndex)要删除元素的索引删除ArrayList某一索引区间的元素
rangeCheck()privatevoid(int index)要检查的索引检查某一索引是否超出了ArrayList的大小
rangeCheckForAdd()privatevoid(int index)要检查的索引在调用add()和addAll()时,检查指定索引是否超出了ArrayList的大小
outOfBoundsMsg()privateString(int index)索引String字符串return "Index: “+index+”, Size: "+size;
removeAll()publicboolean(Collection<?> c)要删除的集合元素true/false集合是否删除成功删除arrayList中的元素
retainAll()publicboolean(Collection<?> c)要保留的集合元素true/false操作是否成功保留只在指定的集合中存在的ArrayList中的元素
batchRemove()privateboolean(Collection<?> c, boolean complement)true/false操作是否成功批量删除ArrayList中的元素
writeObject()privatevoid(java.io.ObjectOutputStream s)ArrayList自定义的序列化方法
readObject()privatevoid(java.io.ObjectInputStream s)ArrayList自定义的序列化方法
listIterator()publicListIterator(int index)指定位置的索引ListItrListItr对象从ArrayList的指定位置开始,返回一个List迭代器
listIterator()publicListIteratorListItrListItr对象从ArrayList的初始位置开始,返回一个List迭代器
Iterator()publicIteratorItrItr对象从ArrayList的初始位置开始,返回一个迭代器
subList()publicList(int fromIndex, int toIndex)new SubList()SubList类对象截取ArrayList指定区间的元素,并返回一个SubList内部类
subListRangeCheck()staticvoid(int fromIndex, int toIndex, int size)索引、ArrayList的大小SubList前的边界检查
spliterator()publicSpliteratornew ArrayListSpliterator<>(this, 0, -1, 0)返回一个ArrayListSpliterator对象
forEach()publicvoid(Consumer<? super E> action)Lamuda表达式循环输出ArrayLIstforeach的底层原理是for循环
removeIf()见下方代码示例publicboolean(Predicate<? super E> filter)Lamuda表达式 (函数式接口)true/false操作是否成功删除ArrayList中满足某条件的值
replaceAll()见下方代码示例publicvoid(UnaryOperator operator)Lamuda表达式 (函数式接口)true/false操作是否成功删除ArrayList中满足某条件的值
sort()见下方代码示例publicvoid(Comparator<? super E> c)Lamuda表达式 (函数式接口)true/false操作是否成功ArrayList排序
  • Java ArrayList中removeIf()的使用
public class DYHTEST{
    static class Person {
        private String name;//姓名
        private Integer age;//年龄
        public Person(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
        public Integer getAge() {
            return age;
        }
        //重写toString,方便观看结果
        @Override
        public String toString() {
            return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
        }
    }
    public static void main(String[] args) {
        ArrayList<Person> arrayList = new ArrayList(){{
            add(new Person("张三", 22));
            add(new Person("王五", 34));
            add(new Person("赵六", 30));
        }};
        //过滤30岁以上的人
        arrayList.removeIf(person -> person.getAge() >= 30);
        System.out.println(arrayList.toString());//查看结果
    }
}
  • 打印信息
    在这里插入图片描述

  • Java ArrayList中replaceAll()的使用

        ArrayList<Integer> arrayList = new ArrayList(){{ add(22);add(34);add(30);}};
        //方式1:三目运算符
        arrayList.replaceAll(a -> a.equals(22)?9999999:1);
        System.out.println(arrayList.toString());//查看结果
        //方式2
        arrayList.replaceAll(a -> {
            if (a > 25)
                a = 88888888;
            return a;
        });
        System.out.println(arrayList.toString());//查看结果
  • Java ArrayList中sort()的使用
        ArrayList<Integer> arrayList = new ArrayList(){{ add(22);add(34);add(30);}};
        //Java8 :lamda表达式
        arrayList.sort((ele1,ele2) -> ele1.compareTo(ele2));
        //Java8 :引用
        arrayList.sort(Integer::compareTo);
        System.out.println(arrayList.toString());//查看结果

5. 内部类

5.1 private class Itr implements Iterator

5.1.1 变量

变量名修饰符类型默认值含义
cursor------int------【游标】要返回的下一个元素的索引
lastRet------int-1已经返回的最后一个元素的索引
expectedModCountint----modCount预期的ArrayList大小改变的次数

5.1.2 方法

名称修饰符返回值类型参数参数释义返回值返回值释义功能
hasNext()publicbooleancursor != size当前游标指向的是否为最后一个元素判断迭代器是否有下一个元素
next()publicE(E) elementData[i]下一个数组元素返回下一个数组元素
remove()publicvoid删除已返回的最后一个元素
forEachRemainingpublicvoid(Consumer<? super E> consumer)Consumer函数式接口,可自定义Lamda表达式为每个剩余元素执行给定的操作,直到所有的元素都已经被处理或行动将抛出一个异常
checkForComodification()finalvoid用来实现fail-fast机制

fail-fast 机制,即快速失败机制,是java集合(Collection)中的一种错误检测机制。当在迭代集合的过程中该集合在结构上发生改变的时候,就有可能会发生fail-fast,即抛出 ConcurrentModificationException异常。fail-fast机制并不保证在不同步的修改下一定会抛出异常,它只是尽最大努力去抛出,所以这种机制一般仅用于检测bug。

  • ArrayList发生fail-fast例子
    List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5));
       Iterator<Integer> iterator = list.iterator();
       int i = 0 ;
       while(iterator.hasNext()) {
          if (i == 3) {
               list.remove(3);
           }
           System.out.println(iterator.next());
           i ++;
       }

原因:
在这里插入图片描述

5.2 private class ListItr extends Itr implements ListIterator

5.2.1 构造函数

    ListItr(int index) {
                super();
                cursor = index;
    }

5.2.2 方法

名称修饰符返回值类型参数参数释义返回值返回值释义功能
hasPrevious()publicbooleantrue/falsetrue/false当前游标(索引)指向的是否是首个元素
nextIndex()publicintcursor游标返回下一个元素对应的索引
previousIndex()publicintcursor-1上一个元素对应的索引返回前一个元素对应的索引
previous()publicE(E) elementData[i]当前游标对应的上一个元素的值返回当前游标对应的上一个元素的值
set()publicvoid(E e)设置已经返回的最后一个元素的值
add()publicvoid(E e)向当前游标位置插入一个值

5.3 private class SubList extends AbstractList implements RandomAccess

  • RandomAccess 是一个标志接口,表明实现这个这个接口的 List 集合是支持《快速随机访问》你可以任意访问该数据结构中的任意一个节点的。也就是说,实现了这个接口的集合是支持 快速随机访问 策略的。如果是实现了这个接口的 List,那么使用for循环的方式获取数据会优于用迭代器获取数据。
  • 对ArrayList进行sublist()操作后返回的是SubList类对象,如果直接对该对象进行序列化操作会导致报错,原因是SubList内部类没有实现序列化接口,解决方法为:new ArrayList(SubList)

5.3.1 类变量

变量名修饰符类型默认值含义
parentprivate finalAbstractList父List
parentOffsetprivate finalint父List偏移量
offsetprivate finalint偏移量
sizeprivate finalintSubList类的长度

5.3.2 构造函数

        SubList(AbstractList<E> parent, int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }

5.3.3 方法

名称修饰符返回值类型参数参数释义返回值返回值释义功能
set()publicE(int index, E e)索引、元素oldValue索引对应的旧值设置SubList指定索引位置的值
get()publicE(int index)索引ArrayList.this.elementData索引对应的值获取SubList指定索引位置的值
size()publicintthis.sizeSubList的长度获取SubList的长度
add()publicvoid(int index, E e)索引、元素向SubList中添加元素
remove()publicE(int index)索引result删除元素的值移除SubList末尾位置的值
removeRange()protectedvoid(int fromIndex, int toIndex)区间删除指定索引区间的值
addAll()publicboolean(Collection<? extends E> c)要添加的集合元素true/false集合是否添加成功ArrayList后追加一个集合
addAll()publicboolean(int index, Collection<? extends E> c)要添加的集合元素及索引true/false集合是否添加成功ArrayList的指定位置追加一个集合(重载)
listIterator()publicListIterator(final int index)指定位置的索引ListItrListItr对象从ArrayList的指定位置开始,返回一个List迭代器
Iterator()publicIteratorItrItr对象从ArrayList的初始位置开始,返回一个迭代器
subList()publicList(int fromIndex, int toIndex)new SubList()SubList类对象截取ArrayList指定区间的元素,并返回一个SubList内部类
rangeCheck()privatevoid(int index)要检查的索引检查某一索引是否超出了ArrayList的大小
rangeCheckForAdd()privatevoid(int index)要检查的索引在调用add()和addAll()时,检查指定索引是否超出了ArrayList的大小
outOfBoundsMsg()privateString(int index)索引String字符串return "Index: “+index+”, Size: "+size;
checkForComodification()finalvoid用来实现fail-fast机制

5.4 static final class ArrayListSpliterator implements Spliterator

Spliteratorjdk8新增用于遍历和分隔一个对象中的元素,这个对象必须实现Spliterator接口,实现这个接口类有Collection,数组等。
Spliterator可以逐个的遍历元素,或者批量的遍历。
Spliterator是一个可以分割的迭代器,可以将Spilterator实例分割成多个小的Spilterator实例。

5.4.1 类变量

变量名修饰符类型默认值含义
listprivate finalArrayListArrayList
indexprivateint【游标】当前索引,在前进/拆分时修改
fenceprivateint默认-1,直到被使用变为最后一个元素的索引【边界值】
expectedModCountprivateint预期的ArrayList改变的次数

5.4.2 构造函数

        /** Create new spliterator covering the given  range */
        ArrayListSpliterator(ArrayList<E> list, int origin, int fence, int expectedModCount) {
            this.list = list; // OK if null unless traversed
            this.index = origin;
            this.fence = fence;
            this.expectedModCount = expectedModCount;
        }

5.4.3 方法

名称修饰符返回值类型参数参数释义返回值返回值释义功能
getFence()privateint最后一个元素的位置最后一个元素的位置初始化fence(最后一个元素的位置)
trySplit()publicArrayListSpliteratornew ArrayListSpliterator()返回一个新分割出的spilterator实例分割list,返回一个新分割出的spilterator实例类似二分法分割,可递归哦
tryAdvance()publicboolean(Consumer<? super E> action)可以是正则表达式booleanboolean返回true时,表示可能还有元素未处理 返回falsa时,没有剩余元素处理了
forEachRemainingpublicvoid(Consumer<? super E> consumer)Consumer函数式接口,可自定义Lamda表达式为每个剩余元素执行给定的操作,直到所有的元素都已经被处理或行动将抛出一个异常
estimateSizepubliclongreturn (long) (getFence() - index)估算剩余长度
characteristicspublicintreturn (long) (getFence() - index)返回特征值

5.4.4 spliterator代码示例

    ArrayList<Integer> arrayList = new ArrayList(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
    Spliterator spliterator = arrayList.spliterator();
    //估算剩余长度
    System.out.println(spliterator.estimateSize());
    //输出剩余的元素
    spliterator.forEachRemaining(System.out::print);

    System.out.println();

    ArrayList<Integer> arrayList1 = new ArrayList(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
    Spliterator spliterator1 = arrayList.spliterator();
    //估算剩余长度
    System.out.println(spliterator1.estimateSize());
    //输出特征值
    System.out.println(spliterator1.characteristics());

    //输出分割后的值
    spliterator1.trySplit().forEachRemaining(System.out::print);

在这里插入图片描述


6. ArrayList的扩容机制

  • ArrayList容量不够时,会采用位运算将容量扩充为原来的【1.5】倍。
  • 无参构造在构造时会初始化为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA -> {} ,并在首次插入元素时,初始化数组容量为 【10】,注意数组容量为10并不意味着size为10。
  • 有参构造传入值为0或集合长度为0时,会初始化为 EMPTY_ELEMENTDATA -> {} ,并在首次插入元素时,初始化数组容量为 【1】,即按照传入的参数来确定创建数组的大小

6.1 自动扩容链路

在这里插入图片描述

ArrayList的自动扩容机制底层借助于native方法实现System.arraycopy,如果频繁的对ArrayList进行扩容,则会进行大量IO操作,导致性能降低。因此通过有参的构造函数预设可存储元素的个数,能够避免ArrayList自动扩容,提高其性能。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值