1、简介

ArrayList是java集合框架常用的集合类之一,底层是基于数组来实现容量大小动态变化的。

2、类图(JDK 1.8)

下图是ArrayList实现的接口和继承的类关系图:

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

1、实现了四个接口

1.1. java.util.List 接口,提供数组的添加、删除、修改、迭代遍历等操作。

1.2. java.util.RandomAccess 接口,表示 ArrayList 支持快速的随机访问。(RandomAccess 是 List 实现所使用的标记接口,用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。)

1.3. java.io.Serializable 接口,表示 ArrayList 支持序列化的功能。

1.4. java.lang.Cloneable 接口,表示 ArrayList 支持克隆。

2、继承了AbstractList抽象类

2.1AbstractList抽象类就是List分支的顶层超类。此类提供了List接口的骨干实现,以最大限度地减少实现由“随机访问”数据存储(例如数组、链表)支持的此接口所需的工作量

三、常用方法

添加元素 add()

    /**
* Appends the specified element to the end of this list.
* 添加单个元素方法
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
//判断如果容量不够,进行扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
//设置到数组末尾,然后在size+1
elementData[size++] = e;
return true;
}
//保证数组大小是否足够,不足则1.5倍扩容
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//计算数组,最小需要的长度
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//new ArrayList()初始化的时候 elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA
//在添加的时候在初始化长度为10的数组
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
} private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//判断数组容量是否足够,不足进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);//数组扩容
} /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
* 数组扩容,增加容量以确保它至少可以容纳最小容量参数指定的元素数
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//新数组长度是旧数组的1.5倍
if (newCapacity - minCapacity < 0)//判断新数组需要的长度,是否比需要数组需要的最小容量小
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)//判断新数组长度是否大于MAX_ARRAY_SIZE【2147483647-8】
newCapacity = hugeCapacity(minCapacity);//判断 最小容量大于MAX_ARRAY_SIZE返回Integer.MAX_VALUE 否则返回 MAX_ARRAY_SIZE
elementData = Arrays.copyOf(elementData, newCapacity);//复制当前数组到一个新数组(长度为newCapacity),并返回
}
//判断 最小容量大于MAX_ARRAY_SIZE返回Integer.MAX_VALUE 否则返回 MAX_ARRAY_SIZE
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}

流程图:

get方法 get()

根据下标获取元素

    public E get(int index) {
rangeCheck(index);//判断当前下标是否数组越界,越界抛出IndexOutOfBoundsException异常
//根据数组下标获取元素
return elementData(index);
}
//判断当前下标是否数组越界,越界抛出IndexOutOfBoundsException异常
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//根据数组下标获取元素
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}

删除元素 remove()

1、public E remove(int index)

删除列表中指定位置的元素。将任何后续元素向左移动

    //根据下标删除数组元素,下标右边元素向左移
public E remove(int index) {
rangeCheck(index);//判断当前下标是否数组越界,越界抛出IndexOutOfBoundsException异常 modCount++;//数组修改+1
E oldValue = elementData(index);//根据下标获取数组元素 int numMoved = size - index - 1;//元素向左移动的长度
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);//当前下标-后续元素向左移动
//先size-1设置null删除元素,方便gc回收
elementData[--size] = null; // clear to let GC do its work return oldValue;//返回旧的值
}

2、public boolean remove(Object o)

删除数组的第一个匹配元素,

    //删除数组的第一个匹配的元素
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);//根据下标删除元素,逻辑同remove(int index)方法
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);//根据下标删除元素,逻辑同remove(int index)方法
return true;
}
}
return false;
}

获取元素下标 indexOf()

    //取得当前元素下标,查找不到返回-1  代码逻辑跟 remove(Object o) 类似
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;
}

时间复杂度

add(E e)方法 添加元素到末尾

时间复杂度为O(1)。

add(int index, E element)方法 添加元素到指定位置

时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。

最好时间复杂度是 O(1) ,最坏时间复杂度是 O(n) ,平均时间复杂度是 O(n) 。

最好时间复杂度发生在末尾添加的情况。

get(int index)方法 获取指定索引位置的元素

数组在内存中是连续的地址空间,可以直接通过下标去数组查找元素,时间复杂度为O(1)。

remove(int index)方法 删除指定索引位置的元素

最好时间复杂度是 O(1) ,最坏时间复杂度是 O(n) ,平均时间复杂度是 O(n) 。

remove(Object o)方法 删除指定元素值的元素

由于要先找到元素 O(n),然后在通过下标删除元素 O(n), 时间复杂度为O(n)。

小结

1、存储一组不唯一(可以有多个元素引用相同的对象),有序的对象,按照插入顺序的保证有序,元素可以重复,支持null元素

2、按照1.5倍的容量去扩容

2.1、非线程安全。解释一下什么是线程安全:

2.2、当多个线程访问某个类,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类为线程安全的。

----《并发编程实战》

多线程并发访问时,得不到正确的结果。

3、适用于查询多的场景,对元素进行频繁的移动或删除场景比较适用LinkedList这种数据结构

java集合-数组ArrayList的更多相关文章

  1. 从源码看Java集合之ArrayList

    Java集合之ArrayList - 吃透增删查改 从源码看初始化以及增删查改,学习ArrayList. 先来看下ArrayList定义的几个属性: private static final int ...

  2. Java集合关于ArrayList

    ArrayList实现源码分析 2016-04-11 17:52 by 淮左, 207 阅读, 0 评论, 收藏, 编辑 本文将以以下几个问题来探讨ArrayList的源码实现1.ArrayList的 ...

  3. Java集合干货——ArrayList源码分析

    ArrayList源码分析 前言 在之前的文章中我们提到过ArrayList,ArrayList可以说是每一个学java的人使用最多最熟练的集合了,但是知其然不知其所以然.关于ArrayList的具体 ...

  4. java集合之ArrayList,TreeSet和HashMap分析

    java集合是一个重点和难点,如果我们刻意记住所有的用法与区别则是不太现实的,之前一直在使用相关的集合类,但是没有仔细研究区别,现在来把平时使用比较频繁的一些集合做一下分析和总结,目的就是以后在需要使 ...

  5. Java集合:ArrayList的实现原理

    Java集合---ArrayList的实现原理   目录: 一. ArrayList概述 二. ArrayList的实现 1) 私有属性 2) 构造方法 3) 元素存储 4) 元素读取 5) 元素删除 ...

  6. 【源码阅读】Java集合之一 - ArrayList源码深度解读

    Java 源码阅读的第一步是Collection框架源码,这也是面试基础中的基础: 针对Collection的源码阅读写一个系列的文章,从ArrayList开始第一篇. ---@pdai JDK版本 ...

  7. Java集合之ArrayList与LinkList

    注:示例基于JDK1.8版本 参考资料:Java知音公众号 本文超长,也是搬运的干货,希望小伙伴耐心看完. Collection集合体系 List.Set.Map是集合体系的三个接口. 其中List和 ...

  8. Java 集合源代码——ArrayList

    (1)可以查看大佬们的 详细源码解析 : 连接地址为 : https://blog.csdn.net/zhumingyuan111/article/details/78884746 (2) Array ...

  9. Java集合:ArrayList (JDK1.8 源码解读)

    ArrayList ArrayList几乎是每个java开发者最常用也是最熟悉的集合,看到ArrayList这个名字就知道,它必然是以数组方式实现的集合 关注点 说一下ArrayList的几个特点,也 ...

随机推荐

  1. AggregateReport V2.2.0

    1. 说明 AggregateReport V2.2.0终于跟大家见面了!从V1.0.0到V2.2.0 宝路听取了很多同学的建议!感谢大家一路的信任与支持! 2. 文章导读 如果不了解此工具的同学,建 ...

  2. Nacos 2.0 正式发布,性能提升 10 倍!!

    3月20号,Nacos 2.0.0 正式发布了! Nacos 简介: 一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台. 通俗点讲,Nacos 就是一把微服务双刃剑:注册中心 + 配置中 ...

  3. Android Studio 安装及配置

    安装时的那些事 •相关链接 [1]:无需翻墙的链接 [2]:Android Studio 安装教程 •从安装到放弃??? 初次接触 Android,并知道了开发 Android APP 的软件--An ...

  4. springboot的拦截器报错plicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]

    解决方案: spingboot的拦截器"index.html"少"/",太粗心了

  5. [.net] 关于Exception的几点思考和在项目中的使用(一)

    本文链接 https://www.cnblogs.com/hubaijia/p/about-exceptions-1.html 关于exception的基本语法和作用,这里不再赘述,下面记录一下我在项 ...

  6. OO_Unit2 多线程电梯总结

    OO_Unit2 多线程电梯总结 相比于Unit1的表达式求导,Unit2的多线程电梯听上去似乎显得更加"高大上".但在完成了3个task的迭代后再回过头去比较这两个单元,我发现其 ...

  7. 《疯狂Kotlin讲义》读书笔记4——流程控制

    流程控制 与Java类似,Kotlin同样提供了两种基本的流程控制结构:分支结构和循环结构. Kotlin提供了 if 和 when 两种分支语句,其中 when 语句可以代替Java的switch语 ...

  8. 17. Vue2.4+新增属性$listeners

    现在我们来讨论一种情况,A组件与C组件怎么通信,我们有多少种解决方案? 我们使用VueX来进行数据管理,但是如果项目中多个组件共享状态比较少,项目比较小,并且全局状态比较少,那使用VueX来实现该功能 ...

  9. 《MySQL必知必会》学习笔记整理

    简介 此笔记只包含<MySQL必知必会>中部分章节的整理笔记.这部分章节主要是一些在<SQL必知必会>中并未讲解的独属于 MySQL 数据库的一些特性,如正则表达式.全文本搜索 ...

  10. etcd简介及集群安装部署使用

    目录 1. 简介 2. Linux下载安装 3. 单机模式启动 4. 指定各集群成员的方式配置集群 5. 使用discovery service的方式配置集群 6. 集群模式下客户端命令行 7. et ...