原作出处: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

java.lang.Object
java.util.AbstractCollection<E>
java.util.AbstractList<E>
java.util.ArrayList<E> All Implemented Interfaces:
Serializable , Cloneable , Iterable <E>, Collection <E>, List <E>, RandomAccess

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

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

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

  1、elementData:

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

  2、size:

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

源码解析:

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

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

  类构造器:

//指定elementData数组大小,不允许初始化大小,小于0,否则抛异常
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {//初始容量大于0
this.elementData = new Object[initialCapacity];//根据传入initalCapacity初始化元素数组
} else if (initialCapacity == 0) {//初始容量为0
this.elementData = EMPTY_ELEMENTDATA;//将属性的空对象赋值给元素数组
} else {//小于0,抛异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
} /**
*当为指定初始化大小时,会给elementData赋值为空集合
  */
public ArrayList() {
      //将属性的无参空对象数组赋值给元素数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
  //党传递的参数为集合类型时,会把集合类型转为数组类型,并赋值给elementData
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)//是否成功转为Object类型数组
elementData = Arrays.copyOf(elementData, size, Object[].class);//不为Object数组的话就进行复制
} else {//判断参数为空,则将空对象数组赋值给元素数组
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}

核心函数:

  1、add:

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

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

  1.1、ensureCapacityInternal:

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

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

  1.2、ensureExplicitCapacity:

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

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

  1.3、grow:

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

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

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

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

  3、indexOf:

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

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

  4、get

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

  public E get(int index) {
rangeCheck(index);//检验索引是否合法 return elementData(index);
}

  4.1 、elementData:

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

   E elementData(int index) {
return (E) elementData[index];
}

  5、remove:

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

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

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. c++中的运算符重载operator2(翁恺c++公开课[31-33]学习笔记)

    上一篇operator1中,大概说了下重载的基本用法,接下来对c++中常见的可重载运算符归一下类,说一下它们的返回值,讨论下较为复杂的运算符重载上的坑

  2. NB-IOT学习

    一 信号穿透力强,覆盖面广(基站少成本低).低功耗(eDRX/PSM省电技术).适合小流量时延要求不高(10s.) 二 主要芯片: 华为:Hi2110/2115,基于此的模组有:中移的M5310 移芯 ...

  3. [HEOI 2013]SAO

    Description 题库连接 给你一个 \(n\) 个节点的有向树,问你这棵树的拓扑序个数,对大质数取模.多测,测试组数 \(T\). \(1\leq n\leq 1000, 1\leq T\le ...

  4. overlay rate

    1.导入nii.img文件,三维矩阵 2.模版矩阵和网络矩阵对应位置元素相乘 .* 3.生成位置为0的新矩阵 cc=(nii_new==0); 4.两个矩阵的非零元素个数   t1=length(ni ...

  5. 使用gitthub 创建项目搭建博客

    最近在学Andrew Ng 的机器学习,做了上买那个的练习题和变成作业,想着把自己做的编程作业放到GitHub,方便讨论,虽然之前注册了GitHub,但这两年整天在毕设方向的事,做的身心俱疲,再加上自 ...

  6. Lesson 11 How to grow old

    What, accoroding to the author is the best way to overcome the fear of death as you get older? Some ...

  7. kill和raise

    kill向特定的进程和进程组发送信号 raise向进程自身发送信号

  8. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 按钮:表示一个危险动作的按钮操作

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  9. Pycharm设置默认HTML模板

    Pycharm设置默认HTML模板 Bootstrap导入链接 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/ ...

  10. java并发初探ReentrantWriteReadLock

    java并发初探ReentrantWriteReadLock ReenWriteReadLock类的优秀博客 ReentrantReadWriteLock读写锁详解 Java多线程系列--" ...