源码解析系列主要对Java的源码进行详细的说明,由于水平有限,难免出现错误或描述不准确的地方,还请大家指出。

1.位置

ArrayList位于java.util包中。

 package java.util;

 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.function.UnaryOperator;

2.变量和常量

先明确一点,ArrayList是采用Object类型的数组实现的。

ArrayList开始定义了一些常量和变量:

private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.     * ArrayList初始化默认容量大小为10,见无参构造函数。
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.     * 空实例共享的空数组实例。
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.     * 默认大小的空实例共享的空数组实例。将它与EMPTY_ELEMENTDATA区分开,以便确定当添加了第一个成员之后扩充多大。     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 

  /**     * The array buffer into which the elements of the ArrayList are stored.     * The capacity of the ArrayList is the length of this array buffer. Any     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA     * will be expanded to DEFAULT_CAPACITY when the first element is added.     * ArrayList成员存储在这个数组缓冲区中。    * 容量大小是这个缓冲区的长度,任何elementDate==DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList    * 在添加第一个成员时都会扩充到DEFAULT_CAPACITY大小,即容量为10。    */ 

    transient Object[] elementData; // non-private to simplify nested class access 

 /**    * The size of the ArrayList (the number of elements it contains).    * ArrayList的大小,注意是实际包含的成员个数。   * @serial    */     private int size;

3.构造函数

ArrayList有三个构造函数:

1)无参构造函数

    /**
     * Constructs an empty list with an initial capacity of ten.     * 构造一个初始容量为10的空list。
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

注意,这里说构造一个初始容量为10的空list,但是赋给elementData的只是一个空的数组(原因后续说明)。

2)带指定初始容量参数的构造函数

 /**
     * Constructs an empty list with the specified initial capacity.
     * 构造一个指定了初始容量的空list。
     * @param  initialCapacity  the initial capacity of the list     *         initialCapacity指定list的初始容量
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative     *         当指定容量值为负值时,抛出IllegalArgumentException异常
     */
    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);
        }
    }

当指定的初始容量值大于零时,新建一个大小为initialCapacity的Object数组,并赋 elementData;

当指定的初始容量值为零时,将 EMPTY_ELEMENTDATA赋给elementData。

3)使用指定Collection构造ArrayList的构造函数

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     * 构造一个包含指定Collection成员的list,成员的排列顺序与使用Collection的     * iterator返回的顺序一致。
     * @param c the collection whose elements are to be placed into this list     *        c 指定的Collection,它的所有元素都会被放在构造的list中
     * @throws NullPointerException if the specified collection is null     *         当指定的Collection为null是抛出NullPointerException异常
     */
    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;
        }
    }

既然是从指定的Collection构造ArrayList,那么成员的类型就要保持不变,即ArrayList中的成员类型与Collection中的成员类型要相同。

先利用toArray()将Collection c转换为数组,并让elementData指向这个数组;

接下来,取出elementData的成员个数并赋值给size;

如果size不为0,则判断elementData的成员类是否与Object类相同,不同则进行一次copy操作,并进行类型转换;

如果size为0,则将elementData指向EMPY_ELEMENTDATA。

4.trimToSize()方法

/**
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.     * 将ArrayList实例的容量trim为list的当前size。     * 应用可以使用这个方法来最小化ArrayList实例的存储空间。
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

modCount用来记录修改次数,modCount主要用于多线程环境下,因为ArrayList是非线程安全的,这里使用了Fail-Fast机制。任何对ArrayList的修改都会增加modCount的值,在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount。在迭代过程中,会判断 modCount是否等于 expectedModCount,如果不等,说明其他线程修改了ArrayList,就要抛出ConcurrentModificationException 异常。

理解这个函数的前提是分清楚size和length的不同之处:

size是ArrayList实际包含的成员个数;而length是ArrayList的容量,即最多容纳多少元素。

比如ArrayList的length可以为10,但是只包含6个成员,其余为null。

trimToSize()方法的目的就是使length等于size,以节约存储空间。

当size小于elementData的length时:

如果size为0,说明 elementData 不包含任何成员,把elementData指向 EMPTY_ELEMENTDATA 即可;

如果size不为0,说明elementData包含成员,这时调用copyOf(),做一次copy,使ArrayList的容量大小和size相等(这里主要目的是理解ArrayList,暂时不对copyOf()进行说明,后续文章详细介绍)。

下篇文章我们主要分析ArrayList的扩容机制。

ArrayList源码解析(一)的更多相关文章

  1. ArrayList源码解析

    ArrayList简介 ArrayList定义 1 public class ArrayList<E> extends AbstractList<E> implements L ...

  2. 顺序线性表 ---- ArrayList 源码解析及实现原理分析

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7738888.html ------------------------------------ ...

  3. 面试必备:ArrayList源码解析(JDK8)

    面试必备:ArrayList源码解析(JDK8) https://blog.csdn.net/zxt0601/article/details/77281231 概述很久没有写博客了,准确的说17年以来 ...

  4. ArrayList源码解析(二)

    欢迎转载,转载烦请注明出处,谢谢. https://www.cnblogs.com/sx-wuyj/p/11177257.html 自己学习ArrayList源码的一些心得记录. 继续上一篇,Arra ...

  5. Java中的容器(集合)之ArrayList源码解析

    1.ArrayList源码解析 源码解析: 如下源码来自JDK8(如需查看ArrayList扩容源码解析请跳转至<Java中的容器(集合)>第十条):. package java.util ...

  6. Collection集合重难点梳理,增强for注意事项和三种遍历的应用场景,栈和队列特点,数组和链表特点,ArrayList源码解析, LinkedList-源码解析

    重难点梳理 使用到的新单词: 1.collection[kəˈlekʃn] 聚集 2.empty[ˈempti] 空的 3.clear[klɪə(r)] 清除 4.iterator 迭代器 学习目标: ...

  7. ArrayList源码解析--值得深读

    ArrayList源码解析 基于jdk1.8 ArrayList的定义 类注释 允许put null值,会自动扩容: size isEmpty.get.set.add等方法时间复杂度是O(1): 是非 ...

  8. 【源码解析】- ArrayList源码解析,绝对详细

    ArrayList源码解析 简介 ArrayList是Java集合框架中非常常用的一种数据结构.继承自AbstractList,实现了List接口.底层基于数组来实现动态容量大小的控制,允许null值 ...

  9. Java集合-ArrayList源码解析-JDK1.8

    ◆ ArrayList简介 ◆ ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAcc ...

随机推荐

  1. 手机自动化测试:Appium源码分析之跟踪代码分析九

    手机自动化测试:Appium源码分析之跟踪代码分析九   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家 ...

  2. 老李分享:Web Services 架构 2

    服务传输层 这一层负责应用之间的消息传输.目前,该层包括了超文本传输协议(HTTP).简单邮件传输协议(SMTP).文件传输协议(FTP).以及一些新兴协议,比如块可扩展交换协议(BEEP). XML ...

  3. scrollWidth,offsetWidth,clientWidth,width;scrollHeight,offsetHeight,clientHeight,height;offsetTop,scrollTop,top;offsetLeft,scrollLeft,left还有谁

    题中的那么多属性让人头都大了,他们到底是什么意思?不同浏览器的实现是一样的吗?以下所有结论来自chrome版本 53.0.2785.89 (64-bit)和firefox版本52.0.2,操作系统ub ...

  4. C++学习笔记之模板篇

    title: C++学习笔记之模板篇 tags: c++,c,模板,vector,friend,static,运算符重载,标准模板 --- 一.模板 不管是函数模板还是类模板,在未初始化前都是不占用内 ...

  5. jmeter 使用jmeter 录制web脚本

    1.打开jmeter.鼠标右击工作台.添加HTTP代理服务器 2.设置端口号.目标控制器.分组 3.添加查看结果树 4.点击启动.确定完成 5.打开浏览器直接进行操作.就可以看到所录制的脚本信息

  6. Python 多进程概述

    multiprocessing python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程.Python提供了非常好用的多进程包mult ...

  7. Java中ArrayList,Vector,LinkedList,HashMap,HashTable,HashSet对比及总结

    1.所有的集合的父类都是Collection的接口 2.Set List Map 区别 A  在Set里面:无法添加元素的顺序,所以Set里面的元素不能重复 B  在List中:有索引号,类似于数组, ...

  8. Git托管

    前面的话 本文将主要介绍如何使用Github来托管Git服务 SSH 大多数Git服务器都会选择使用SSH公钥来进行授权.系统中的每个用户都必须提供一个公钥用于授权 首先先确认一下是否已经有一个公钥了 ...

  9. chrome浏览器tab页内存占用变大,网站变慢为哪般?

    问题概述: 公司做的是BS应用. 之前我们的后台服务器程序是带状态的,用ehcache存储登录状态:这两天被我改成了redis存储,应用本身不再存储登录状态. 然后自测,我在测试某个很耗时间的网页操作 ...

  10. 利用jackson-databind,复杂对象对象和json数据互转

    如果简单对象,那么转换的方式比较多,这里指的复杂对象,是指对象里面存在cycle引用,比如: /** * @author ding * */@Entity@Table(name = "ser ...