一、ArrayList

ArrayList继承了AbstractList分别实现了List、RandomAccess(随机访问)、Cloneable(可被克隆(复制的意思))、

Serializable(可序列化)

public class ArrayList<E> extends AbstractList<E>

implements List<E>, RandomAccess, Cloneable, java.io.Serializable

1.1、RandomAccess(随机访问)

该接口是List实现来指示它们支持快速(通常是固定时间)随机访问。主这个接口的目的是允许通用算法改变它们行为提供良好的性能时,适用于随机或顺序访问列表。

操作随机访问列表的最佳算法

(如 ArrayList),

应用于可产生二次行为顺序访问列表(如LinkedList)。

通用的列表建议使用算法检查给定列表是否为

instanceof这个接口之前,应用的算法会

如果应用于顺序访问列表,则性能较差,

并在必要时改变他们的行为,以确保他们的行为是可接受的

性能。

例子:

若是列表很大时,某些List实现提供渐进的线性访问时间,但实际上的访问时间是固定的。这样的List实现通常应该实现此接口。实际经验证明,如果是下列情况,则

List实现

对于类的典型实例,这个循环:

for (int i=0, n=list.size(); i < n; i++)

list.get(i);

运行速度比这个循环快:

for (Iterator i=list.iterator(); i.hasNext(); )

i.next();

1.2实现Cloneable接口的作用

类实现了Cloneable接口,以向Object.clone()方法表明,该方法对该类的实例进行字段对字段的复制是合法的。

没实现Cloneable接口的实例上调用Object(对象)的clone(克隆)方法将导致抛出异常CloneNotSupportedException。

按照惯例,实现此接口的类应该使用公共方法重写对象Object.clone(它是受保护的)。有关覆盖此方法的详细信息,请参阅java.lang.Object.clone()。

请注意,此接口不包含clone(克隆)方法。因此,仅凭对象实现此接口这一事实是不可能clone(克隆)对象的。即使反射性地调用clone(克隆)方法,也不能保证它会成功。

1.3实现Serializable接口的作用:

类的可序列化性是由实现java.io的类来启用的。Serializable接口。不实现此接口的类将不会对其任何状态进行序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。

2.ArrayList.class

2.1 ArrayList成员变量

/**

* 声明serialVersionUID的值,确保serialVersionUID值跨不同JAVA编译器实现的一致性(版本的兼容性)。

* 强烈建议使用Private修饰符显示声明serialVersionUID

* serialVersionUID字段作为继承成员没有用处

*/

private static final long serialVersionUID = 8683452581122892189L;

/**

* 默认初始容量。(ArrayList底层是数组结构)

*/

private static final int DEFAULT_CAPACITY = 10;

/**

* 用于空实例的共享空数组实例。(当指定数组的容量为0时使用这个常量赋值)

*/

private static final Object[] EMPTY_ELEMENTDATA = {};

/**

* 用于默认大小的空实例的共享空数组实例。我们

* 将其与EMPTY_ELEMENTDATA区分开来,以了解何时膨胀多少

* 添加第一个元素。(默认空参构造函数时使用这个常量赋值)

*/

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**

* 存储ArrayList元素的数组缓冲区。

* ArrayList的容量是这个数组缓冲区的长度。

* 即元素数组:真正存放数据的对象数组,transient标识不被序列化

*/

transient Object[] elementData; // 非私有以简化嵌套类访问

/**

* ArrayList的大小(它包含的元素的数量)。

*/

private int size;

/**

* 分配的数组的最大值。

*/

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**

* 修改次数

* /

protected transient int modCount = 0;

2.2 ArrayList构造方法

/**

*指定初始容量的大小。

*/

public ArrayList(int initialCapacity) {

if (initialCapacity > 0) {//在容量大于零的条件下,指定多大容量就是多大

this.elementData = new Object[initialCapacity];

} else if (initialCapacity == 0) {//没有指定容量大小,则为空数组

this.elementData = EMPTY_ELEMENTDATA;//构造一个空的List其size为DEFAULT_CAPACITY = 10的空列表。

} else {//如果指定容量大小为负责,抛出异常IllegalArgumentException

throw new IllegalArgumentException("Illegal Capacity: "+

initialCapacity);

}

}

/**

* 构造一个空的List其size为DEFAULT_CAPACITY = 10的空列表。

*/

public ArrayList() {

this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

/**

* 传入一个Collection初始化ArrayList

*/

public ArrayList(Collection<? extends E> c) {

elementData = c.toArray();//把给定的集合转换成Object[]数组

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);

//复制的数组,返回副本的长度,返回副本的类→→→新的数组[]

} else {

//elementData的length为空,直接将ArrayList的数组转为空数组

// replace with empty array.

this.elementData = EMPTY_ELEMENTDATA;

}

}

//将ArrayList实例的容量调整为列表的当前大小。

//应用程序可以使用此操作最小化ArrayList实例的存储。

public void trimToSize() {

modCount++;//修改次数+1

if (size < elementData.length) {

//如果底层数组的length为空则置为EMPTY_ELEMENTDATA

//否则使用Arrays的方法对复制元素

elementData = (size == 0)

? EMPTY_ELEMENTDATA

: Arrays.copyOf(elementData, size);

}

}

2.3常用方法add

2.3.1add(E a)与add(int index,E element);

//将指定的元素追加到此列表的末尾。

public boolean add(E e) {

ensureCapacityInternal(size + 1);  // Increments modCount!!

elementData[size++] = e;//元素添加到此列表中

return true;

}

add调用了函数→ensureCapacityInternal(int size)代码如下:

private void ensureCapacityInternal(int minCapacity) {

//若当前数组是空数组

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

//则比较加入的个数与默认个数(10)比较,取较大值

minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

}

ensureExplicitCapacity(minCapacity);

}

我的理解是此函数是确认ArrayList底层数组elementData有适合的大小;

然后ensureCapacityInternal(int minCapacity)函数调用

ensureExplicitCapacity(minCapacity)代码如下:

private void ensureExplicitCapacity(int minCapacity) {

modCount++;//修改次数+1

// overflow-conscious code(溢出)

//判断数组真实元素个数加1后的长度与当前数组长度大小关系,

//如果小于0,返回,如果大于0,则

//调用grow(minCapacity)方法

if (minCapacity - elementData.length > 0)//数组放不下

grow(minCapacity);//扩容

}

ensureExplicitCapacity(int minCapacity)此函数调用了

grow(minCapacity)函数

/**

* 增加容量,以确保它至少可以容纳由最小容量参数指定的元素数量。

*/

private void grow(int minCapacity) {

// overflow-conscious code

//老容量

int oldCapacity = elementData.length;

//新容量为原来的1.5倍

int newCapacity = oldCapacity + (oldCapacity >> 1);

//新容量 小于 参数指定的容量,修改新容量

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);

}

ArrayList动态增大主要是依赖于外汇常见问题grow(int minCapacity)方法调用

Arrays.copyOf(elementData, newCapacity);

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {

@SuppressWarnings("unchecked")

T[] copy = ((Object)newType == (Object)Object[].class)

? (T[]) new Object[newLength]

: (T[]) Array.newInstance(newType.getComponentType(), newLength);

System.arraycopy(original, 0, copy, 0,

Math.min(original.length, newLength));

return copy;

}

总结:

add函数的调用过程

ArrayList 内部使用数组存储元素,当数组长度不够时进行扩容,每增加自身一半的空间,ArrayList不会进行缩小容容量;

ArrayList默认初始化容量为10,底层是数组结构;

线程不安全;

Key有序,value不可重复的;

ArrayList 支持随机访问,通过索引访问元素快,时间复杂度为O(1);

ArrayList 添加元素到尾部快,平均时间复杂度为O(1);

ArrayList 添加元素到中间比较慢,因为要搬移元素,平均时间复杂度为O(n);

ArrayList 从尾部删除元素快,平均时间复杂度为O(1);

ArrayList 从中间删除元素比较慢,因为要搬移元素,平均时间复杂度为O(n);

————————————————

原文链接:https://blog.csdn.net/weixin_44903953/article/details/102880906

Java基础之ArrayList类的更多相关文章

  1. Java基础系列-ArrayList

    原创文章,转载请标注出处:<Java基础系列-ArrayList> 一.概述 ArrayList底层使用的是数组.是List的可变数组实现,这里的可变是针对List而言,而不是底层数组. ...

  2. Java基础-DButils工具类(QueryRunner)详解

    Java基础-DButils工具类(QueryRunner)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 如果只使用JDBC进行开发,我们会发现冗余代码过多,为了简化JDBC ...

  3. Java基础之File类的使用

    Java基础之File类的使用 1.File类的构造方法和常用方法 2.对File中listFile(FileNameFilter name)学习 3.与File文件类相关的实现 File类的构造方法 ...

  4. Java常用API(ArrayList类)

    Java常用API(ArrayList类) 我们为什么要使用ArrayList类? 为了更加方便的储存对象,因为使用普通的数组来存储对象太过麻烦了,因为数组的一个很大的弱点就是长度从一开始就固定了,所 ...

  5. Java基础(44):ArrayList使用详解

    1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处:    a.动态的增加和减少元素    b.实现了IColle ...

  6. Java基础:Object类中的equals与hashCode方法

    前言 这个系列的文章主要用来记录我在学习和复习Java基础知识的过程中遇到的一些有趣好玩的知识点,希望大家也喜欢. 一切皆对象   对于软件工程来说面向对象编程有一套完整的解决方案:OOA.OOD.O ...

  7. 【Java基础】常用类

    常用类 字符串相关的类 String类:代表字符串,使用一对 "" 引起来表示. public final class String implements java.io.Seri ...

  8. java基础-01代理类

    简单的代理类实现案例主实现类:ProxyTestimport java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;im ...

  9. java基础之常用类1

    java基础 以下内容为本人的学习笔记,如需要转载,请声明原文链接   java常用类: 1.内部类 2.Object类 3.Object类常用方法 4.包装类 5.String类 6.BigDeci ...

随机推荐

  1. js对象的深度拷贝

    //判断对象的类型 Array Object Function String Number ..... function getObjType(obj){ return Object.prototyp ...

  2. pycharm查找替换快捷键

    查找:CTRL + F 替换:CTRL + R 如果想删除,替换那一栏不填就可以了

  3. SQL Server 管理套件(SSMS)

    SQL Server 管理套件(SSMS) 当您按照之前章节的步骤顺利安装完 SQL Server 2014 后,要做的第一件事就是需要打开 SQL Server 管理套件,并且要知道怎样去使用它. ...

  4. SQL Wildcards 通配符

    SQL Wildcards通配符 通配符用于替换字符串中的任何其他字符. 通配符与SQL LIKE运算符一起使用.在WHERE子句中使用LIKE运算符来搜索列中的指定模式. 有两个通配符与LIKE运算 ...

  5. 【Guava】Guava Cache用法

    背景 缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用.在日长开发有很多场合,有一些数据量不是很大,不会经常改动,并且访问非常频繁.但是由于受限于硬盘IO的性能或者远程网络 ...

  6. teradata在虚拟机安装客户端sql Assistant

    学习链接:https://www.w3cschool.cn/teradata/? 1.安装过程

  7. ARMv8 架构与指令集.学习笔记

    目 录 第1章 ARMv8简介. 3 1.1基础认识. 3 1.2 相关专业名词解释. 3 第2章 Execution State 4 2.1 提供两种Execution State 4 2.2 决定 ...

  8. MacBook Pro 快捷键2

    Mac 键盘快捷键 您可以按下组合键来实现通常需要鼠标.触控板或其他输入设备才能完成的操作.   要使用键盘快捷键,请按住一个或多个修饰键,同时按快捷键的最后一个键.例如,要使用快捷键 Command ...

  9. C++构造函数异常(一)

    C++ 构造函数的异常是一个比较难缠的问题,很多时候,我们可能不去考虑这些问题,如果被问到,有人可能会说使用RAII管理资源. 但你真的考虑过如果构造函数失败了,到底会发生什么吗,前面构造成功的成员. ...

  10. 【扩展lucas定理】

    洛谷模板题面:https://www.luogu.org/problemnew/show/P4720 扩展卢卡斯被用于解决模数为合数情形下的组合数问题. 首先我们把模数mod质因数分解,解决模每个素数 ...