原作出处:https://www.cnblogs.com/leesf456/p/5308358.html

简介:

  1、ArrayList是一个数组队列,相当于动态数组。与java中的数组相比,它的容量能动态增长,它继承与AbstractList,实现List,RandomAccess,Cloneable,java.io.Serizlizable这些接口

  2、ArrayList继承AbstractList,实现了List,它是一个数组队列,提供了相关的增、删、改、遍历等功能

  3、ArrayList实现了RandomAccess接口,即提供了随机访问功能。RandomAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。

  4、ArrayList实现了Cloneable接口,即覆盖了函数clone(),能被克隆

  5、ArrayList实现了java.io.Serizlizable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

  6、ArrayList不是线程安全的,在单线程中才使用

数据结构:参考API1.8文档 的ArrayList

  1. java.lang.Object
  2. java.util.AbstractCollection<E>
  3. java.util.AbstractList<E>
  4. java.util.ArrayList<E>
  5.  
  6. All Implemented Interfaces:
  7. Serializable Cloneable Iterable <E>, Collection <E>, List <E>, RandomAccess

ArrayList构造函数:参考API1.8文档 的ArrayList

  1. ArrayList()
  2. 构造一个初始容量为十的空列表。
  3. ArrayList(Collection<? extends E> c)
  4. 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
  5. ArrayList(int initialCapacity)
  6. 构造具有指定初始容量的空列表。

ArrayList包含了两个重要的对象:

  1、elementData:

    elementData是“Object []类型的数组”,它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10,elementData数组的大小会根据ArrayList容量的增长而动态的增长

  2、size:

    size则是动态数组的实际大小。

源码解析:

  类属性:类属性中核心的属性为elementData,类型为Object[],用于存放实际元素,并且被标记为transient,也就意味着在序列化的时候,此字段是不会被序列化的 

  1.  //序列版本号
  2. private static final long serialVersionUID = 8683452581122892189L;
  3.     //初始容量为10
  4. private static final int DEFAULT_CAPACITY = 10;
  5.     //空对象数组
  6. private static final Object[] EMPTY_ELEMENTDATA = {};
  7.     //(无参)缺省空对象数组
  8. private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  9.     //元素数组
  10. transient Object[] elementData;
  11.     //实际元素大小
  12. private int size;
        //最大数组容量
  13.  
  14.   private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

  类构造器:

  1. //指定elementData数组大小,不允许初始化大小,小于0,否则抛异常
    public ArrayList(int initialCapacity) {
  2. if (initialCapacity > 0) {//初始容量大于0
  3. this.elementData = new Object[initialCapacity];//根据传入initalCapacity初始化元素数组
  4. } else if (initialCapacity == 0) {//初始容量为0
  5. this.elementData = EMPTY_ELEMENTDATA;//将属性的空对象赋值给元素数组
  6. } else {//小于0,抛异常
  7. throw new IllegalArgumentException("Illegal Capacity: "+
  8. initialCapacity);
  9. }
  10. }
  11.  
  12. /**
  13. *当为指定初始化大小时,会给elementData赋值为空集合
      */
    public ArrayList() {
  1.       //将属性的无参空对象数组赋值给元素数组
  2. this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  3. }
  4.   //党传递的参数为集合类型时,会把集合类型转为数组类型,并赋值给elementData
  5. public ArrayList(Collection<? extends E> c) {
  6. elementData = c.toArray();//转为数组并赋值给元素数组
  7. if ((size = elementData.length) != 0) {//判断参数为非空集合
  8. // c.toArray might (incorrectly) not return Object[] (see 6260652)
  9. if (elementData.getClass() != Object[].class)//是否成功转为Object类型数组
  10. elementData = Arrays.copyOf(elementData, size, Object[].class);//不为Object数组的话就进行复制
  11. } else {//判断参数为空,则将空对象数组赋值给元素数组
  12. // replace with empty array.
  13. this.elementData = EMPTY_ELEMENTDATA;
  14. }
  15. }

核心函数:

  1、add:

    在add函数还有ensureCapacityInternal,此函数可以理解为确保elementData数组有合适的大小。

  1. public boolean add(E e) {//添加元素
  2. ensureCapacityInternal(size + 1); // Increments modCount!!
  3. elementData[size++] = e;
  4. return true;
  5. }

  1.1、ensureCapacityInternal:

    在ensureCapacityInternal方法中ensureExplicitCapacity是为了确保elementData元素数组有合适的大小

  1. private void ensureCapacityInternal(int minCapacity) {
        
  2. if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//判断元素数组是否为空
  3. minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//取较大值
  4. }
  5.  
  6. ensureExplicitCapacity(minCapacity);
  7. }

  1.2、ensureExplicitCapacity:

    grow方法才会对数组进行扩容,1.1、1.2都只是过程,最后完成实际扩容操作是grow方法

  1. private void ensureExplicitCapacity(int minCapacity) {
  2. modCount++;//结构性修改+1
  3.  
  4. // overflow-conscious code
  5. if (minCapacity - elementData.length > 0)
  6. grow(minCapacity);
  7. }

  1.3、grow:

    正常情况下会扩容1.5倍,特殊情况下(新扩展数组大小已达到最大值)则只取最大值

  1. private void grow(int minCapacity) {
  2. // overflow-conscious code
  3. int oldCapacity = elementData.length;//元素数组大小(旧容量)
  4. int newCapacity = oldCapacity + (oldCapacity >> 1);//新容量为旧容量的1.5倍
  5. if (newCapacity - minCapacity < 0)//新容量小于参数指定容量,修改新容量
  6. newCapacity = minCapacity;
  7. if (newCapacity - MAX_ARRAY_SIZE > 0)//新容量大于最大容量
  8. newCapacity = hugeCapacity(minCapacity);//指定新的容量
  9. // minCapacity is usually close to size, so this is a win:
  10. elementData = Arrays.copyOf(elementData, newCapacity);
  11. }

  2、set:设定指定下标索引的元素值

  1. public E set(int index, E element) {
  2. rangeCheck(index);//检验索引是否合法,否则抛异常
  3.  
  4. E oldValue = elementData(index);//旧值
  5. elementData[index] = element;//赋新值
  6. return oldValue;//返回旧值
  7. }

  3、indexOf:

    从头开始查找与指定元素相等的元素。注意是可以查找Null元素的,意味着ArrayList中可以存放null元素的。与此对应的lastIndexOf,表示从尾部开始查找

  1. //从首开始查找数组里面是否存在指定元素
    public int indexOf(Object o) {
  2. if (o == null) {//判断元素是否为空
  3. for (int i = 0; i < size; i++)//遍历数组
  4. if (elementData[i]==null)//找到第一个为空的元素
  5. return i;//返回它的下标
  6. } else {//元素不为空
  7. for (int i = 0; i < size; i++)//遍历数组
  8. if (o.equals(elementData[i]))//找到第一个和指定元素相等的元素
  9. return i;//返回下标
  10. }
        
  11. return -1;//没有找到,返回-1
  12. }

  4、get

   get方法会检查索引是否合法(只检查是否大于size,而没有检查是否小于0)

  1. public E get(int index) {
  2. rangeCheck(index);//检验索引是否合法
  3.  
  4. return elementData(index);
  5. }

  4.1 、elementData:

    返回值都经过了向下 转型(Object(elementData元素数组是Object类型的)->E),这些是对我们应用程序屏蔽的小细节

  1. E elementData(int index) {
  2. return (E) elementData[index];
  3. }

  5、remove:

    移除指定下标的元素,此时会把指定下标到数组末尾的元素向前移动一个单位,并且会把数组最后一个元素设置为NUll,这样是为了方便之后将这个数组不被使用时,会被GC(垃圾回收),可以做为小的技巧使用

  1. public E remove(int index) {
  2. rangeCheck(index);//检查索引是否合法
  3.  
  4. modCount++;
  5. E oldValue = elementData(index);
  6.  
  7. int numMoved = size - index - 1;//需要移动的元素的个数
  8. if (numMoved > 0)
  9. System.arraycopy(elementData, index+1, elementData, index,
  10. numMoved);
        //赋值为空,有利于进行GC(垃圾回收)
  11. elementData[--size] = null; // clear to let GC do its work
  12.     //返回旧值
  13. return oldValue;
  14. }

java基础源码 (6)--ArrayListt类的更多相关文章

  1. java基础源码 (1)--String类

    这个是String类上面的注释,我用谷歌翻译翻译的,虽然有点语法上的问题,但是大概都可以翻译出来 /** * The {@code String} class represents character ...

  2. java基础源码 (2)--StringBuilder类

    Serializable(接口): 是一个IO的序列化接口,实现了这个接口,就代表这个类可以序列化或者反序列化,该接口没有方法或者字段,仅用于标识可串行话的语义. Appendable(接口): /* ...

  3. java基础源码 (5)--reflect包-AccessibleObject类

    学习参考博客:https://blog.csdn.net/benjaminzhang666/article/details/9664585AccessibleObject类基本作用 1.将反射的对象标 ...

  4. java基础源码 (3)--Annotation(注解)

    借鉴博客地址:https://www.cnblogs.com/skywang12345/p/3344137.html /** * The common interface extended by al ...

  5. java基础源码 (4)--reflect包-AnnotatedElement接口

    接口:AnnotatedElement * Represents an annotated element of the program currently running in this * VM. ...

  6. 自学Java HashMap源码

    自学Java HashMap源码 参考:http://zhangshixi.iteye.com/blog/672697 HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提 ...

  7. Java基础-DBCP连接池(BasicDataSource类)详解

    Java基础-DBCP连接池(BasicDataSource类)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程 ...

  8. java集合源码分析(三):ArrayList

    概述 在前文:java集合源码分析(二):List与AbstractList 和 java集合源码分析(一):Collection 与 AbstractCollection 中,我们大致了解了从 Co ...

  9. java集合源码分析(六):HashMap

    概述 HashMap 是 Map 接口下一个线程不安全的,基于哈希表的实现类.由于他解决哈希冲突的方式是分离链表法,也就是拉链法,因此他的数据结构是数组+链表,在 JDK8 以后,当哈希冲突严重时,H ...

随机推荐

  1. Spring boot 中发送邮件

    参考:https://blog.csdn.net/qq_39241443/article/details/81293939 添加依赖: <dependency> <groupId&g ...

  2. python学习笔记(3) -- 字符与数字之间的转换函数

    转载:python中的字符数字之间的转换函数 int(x [,base ])         将x转换为一个整数     long(x [,base ])        将x转换为一个长整数     ...

  3. Android开发实例之miniTwitter登录界面的实现

    原文: http://www.jizhuomi.com/android/example/134.html 本文要演示的Android开发实例是如何完成一个Android中的miniTwitter登录界 ...

  4. 「SP10628 COT - Count on a tree」

    主席树的综合运用题. 前置芝士 可持久化线段树:其实就是主席树了. LCA:最近公共祖先,本题需要在\(\log_2N\)及以内的时间复杂度内解决这个问题. 具体做法 主席树维护每个点到根节点这一条链 ...

  5. linux安装jdk并设置环境变量(看这一篇文章即可)

    1.查看linux位数 查看linux是32位还是64位,影响需要下载JDK的版本   系统位数 jdk位数 x86(32位) 32位 x86_64(64位) 32位 64位 在linux命令输入: ...

  6. express框架开发接口部署线上环境PM2

    1.PM2介绍 PM2是一个线上环境下,用于启动nodejs进程守护的工具,用来保证服务的稳定及分摊服务器进程和压力. 2.下载安装 npm install pm2 -g  => pm2 --v ...

  7. 搭建 nginx + rtmp 媒体服务器笔记

    工作需要搭建一个流媒体服务器,用来接收前端推过来的视频流,达到实时保存的目的. 具体步骤网上已经比较详细了 可以参考下面这个文档参考文档 https://www.cnblogs.com/monjeo/ ...

  8. express框架安装及中间件原理

    本文主要介绍express中间件的原理,来应对面试. 1.安装express及初始化: npm install express-generator -g   =>   express expre ...

  9. 基于金山快盘的Git服务器、快盘+ Git GUI 实现代码版本管理

        Git,这货堪称神器,用了它就再也不想用其他VCS了,就像上了高速就不想再走国道一样. Git的强大之处在于,你可以在局域网内的任何一个共享路径下创建仓库,而不需要运行任何服务.所有的操作都是 ...

  10. Xcode 9.0 报错,Safe Area Layout Guide Before IOS 9.0

    解决方案就是: 第一步 第二步 第三步 重新编译.