ArrayList源码翻译

  • 简介
  • 属性解读
  • 初始化
  • 添加方法
  • get方法
  • set方法
  • remove方法
  • contains方法
  • clone方法
  • 总结

简介

ArrayList 是 java 集合框架中比较常用的数据结构,其本质是数组。继承自 AbstractList,实现了 List 接口。底层基于数组实现容量大小动态变化。允许 null 的存在。同时还实现了 RandomAccess、Cloneable、Serializable 接口,所以ArrayList 是支持快速访问、复制、序列化的。
JDK1.8源码如下:

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

具体图解如下:

属性解读

    /*** serialVersionUID 用来表明类的不同版本间的兼容性。*序列化的时候,被序列化的类要有一个唯一标记。*客户端和服务端必须需要同一个对象,serialVersionUID的唯一值判定其为同一个对象。*后面的号码是自动生成的,只要是唯一的就行,通常为1。*此行语句去掉在练习的时候也没有什么影响,只不过此实例类会报一个警告。*将鼠标放到警告上,选择第一个解决方案,就会重新加上此行语句,后面的数字和原先的可能会不一样。*/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;/***记录ArrayList(数组)的长度*/private int size;/***定义数组的最大长度为int的最大值减8,即2147483647 - 8或(2^31 - 1 - 8)*/private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

初始化

/**
*无参构造
*将当前数组赋为共享空数组实例
*等同于 this.elementData ={};
*/public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}/***有参构造*/public ArrayList(int initialCapacity) {if (initialCapacity > 0) {//传值大于0将当前数组赋为创建的指定大小的数组实例this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {//传值等于0将当前数组赋为共享空数组实例this.elementData = EMPTY_ELEMENTDATA;} else {//抛出异常-参数不合法throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}
/**
*使用指定 Collection 来构造 ArrayList 的构造函数
*/
public ArrayList(Collection<? extends E> c) {elementData = c.toArray();//将 Collection 转化为数组并赋给 elementDataif ((size = elementData.length) != 0) {//数组长度不等于0if (elementData.getClass() != Object[].class)//如果elementData 的 class 类型不是 Object[],则转换为数组在赋值elementData = Arrays.copyOf(elementData, size, Object[].class);} else {//数组长度等于0,将当前数组赋为共享空数组实例this.elementData = EMPTY_ELEMENTDATA;}}

添加方法

public boolean add(E e) {//确定容量,动态扩容//既然调用add方法那么就要增加一个元素,所以传当前大小size+1来看是否需要扩容ensureCapacityInternal(size + 1);  //将数据添加到数组里;数组大小加一elementData[size++] = e;return true;}private void ensureCapacityInternal(int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//如果是空的数组,取默认容量10和添加元素后容量中最大的值minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);}private void ensureExplicitCapacity(int minCapacity) {//继承于AbstractList。这个成员变量记录着集合的修改次数,也就是每次add或者remove它的值都会加1。//使用迭代器迭代时,Iterator iterator=arrayList.iterator();//返回new Itr() 这个类实现 Iterator<E>// int expectedModCount = modCount;//使用next遍历时检查expectedModCount == modCount//不相等throw new ConcurrentModificationException();//例如两个线程操作同意list,一个遍历,一个添加或删除,当遍历线程遍历出某个元素,这时修改线程执行modCount++,那么遍历线程遍历下一个元素时expectedModCount < modCount,遂抛出异常modCount++;// 检查添加元素后容量大小是否超过当前数组大小if (minCapacity - elementData.length > 0)//超过当前数组大小则需要扩容grow(minCapacity);}
private void grow(int minCapacity) {//当前数组的长度int oldCapacity = elementData.length;//位运算,右移n位->除以2的n次方;左移n位->乘以2的n次方//也就是说新的长度是原来的1.5倍int newCapacity = oldCapacity + (oldCapacity >> 1);//1.5倍长度比添加元素后的长度(也可能是默认的10)小if (newCapacity - minCapacity < 0)//把添加元素后的长度(也可能是默认的10)当作新数组的长度newCapacity = minCapacity;//如果1.5倍长度比定义的最大数组还大...if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);//将原来数组数据拷贝到扩容后的新数组中elementData = Arrays.copyOf(elementData, newCapacity);private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) //抛出异常 溢出(不太清楚这种情况怎样发生)throw new OutOfMemoryError();//添加元素后的容量大小 > 定义的最大数组大小返回整型最大值即 2,147,483,647(2^31 - 1)//否则返回定义的最大数组大小 即 整型的最大值 - 8//三目运算符,问号前面表达式返回true,整个表达式返回冒号前面的值,否则返回冒号后面的值return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;}}

get方法

public E get(int index) {rangeCheck(index);//如果传值大于数组大小,抛出异常return elementData(index);//返回数组对应下标的元素}private void rangeCheck(int index) {if (index >= size)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}E elementData(int index) {return (E) elementData[index];}

set方法

public E set(int index, E element) {rangeCheck(index);//如果传值大于数组大小,抛出异常E oldValue = elementData(index);//取原来该下标的元素elementData[index] = element;//将新元素放到数组该下标的位置return oldValue;//返回原来的元素}

remove方法

public E remove(int index) {rangeCheck(index);//如果传值大于数组大小,抛出异常modCount++;//集合的修改次数加一E oldValue = elementData(index);//取该下标原来的值int numMoved = size - index - 1;//需要移动的元素的个数if (numMoved > 0)//例{0,1,2,3,4,5,6,7,8,9}移除6,则需要将6后面的7,8,9向前移动一位//拷贝方法  从原数组     拷贝开始下标为    拷贝到目标数组         开始下标是     需要拷贝的元素个数
System.arraycopy(elementData,    index+1,       elementData,           index,       numMoved);//将数组空出的位置置为空,数组大小减一,GC工作(这块儿还不懂)elementData[--size] = null; // clear to let GC do its workreturn oldValue;//返回原来的元素}

contains方法

public boolean contains(Object o) {return indexOf(o) >= 0;//true表示存在}public int indexOf(Object o) {if (o == null) {//元素为空,遍历查找第一个为null的下标for (int i = 0; i < size; i++)if (elementData[i]==null)return i;} else {//元素不为空,使用equals方法比较是否相同,相同返回下标for (int i = 0; i < size; i++)if (o.equals(elementData[i]))return i;}//没有找到返回-1return -1;}
Object类
public boolean equals(Object obj) {return (this == obj);}

clone方法

public Object clone() {try {//浅拷贝,把原对象完整的拷贝过来包括其中的引用//因为包括引用所以原对象改变,拷贝对象随之改变//基本数据类型的成员变量会直接进行值传递,拷贝后是两份不同的数据所以原对象改变,拷贝对象不变,即达到深拷贝的目的//引用数据类型的成员变量还需要申请存储空间,并复制每个引用数据类型成员变量所引用的对象,以达到深拷贝的目的ArrayList<?> v = (ArrayList<?>) super.clone();//重新拷贝可变对象->深拷贝v.elementData = Arrays.copyOf(elementData, size);v.modCount = 0;return v;} catch (CloneNotSupportedException e) {// this shouldn't happen, since we are Cloneablethrow new InternalError(e);}}

总结

ArrayList本质上是数组,因此具有数组的特征,具体整理如下:

1.内存地址是连续的,数据存放是顺序的。可能造成不连续内存块造成浪费。实现了RandomAccess这个接口,支持快速随机访问。

2.ArrayList元素是不唯一的(可存放重复元素),可以存放null。

3.插入、删除需要对数组中插入、删除位置之后的元素进行位置调整(整体向 前/后 移也就是拷贝复制),当数据量较大时造成不能忽视的性能损耗

4.存储了数据时最小是10,扩容时长度多数会是原来的1.5倍,最大长度是整型的最大值。那么当扩容后恰好是最大长度或者是接近的长度,但是只需要添加1个或者不多的元素,这种情况下也会造成内存的浪费。

5.ArrayList是线程不安全的。(在上面判断是否需要扩容的ensureExplicitCapacity方法中的modCount++;处有提及)

ArrayList源码翻译相关推荐

  1. ArrayList源码解析与相关知识点

    ArrayList源码解析于相关知识点(超级详细) 文章目录 ArrayList源码解析于相关知识点(超级详细) ArrayList的继承关系 Serializable标记接口 Cloneable标记 ...

  2. java1.8 indexes_java1.8源码之ArrayList源码解读

    文章目录 一.ArrayList概述1.1 ArrayList简介1.2 ArrayList数据结构 二.ArrayList源码分析2.1 ArrayList继承结构和层次关系2.2 类的属性2.3 ...

  3. JDK12下的ArrayList源码解读 与 Vector的对比

    ArrayList源码阅读. //测试代码实现如下 private static void arrayList() {ArrayList<String> list = new ArrayL ...

  4. java function获取参数_「Java容器」ArrayList源码,大厂面试必问

    ArrayList简介 ArrayList核心源码 ArrayList源码分析 System.arraycopy()和Arrays.copyOf()方法 两者联系与区别 ArrayList核心扩容技术 ...

  5. java list addall源码_Java集合:ArrayList源码分析

    其实我看到已有很多大佬写过此类文章,并且写的也比较清晰明了,那我为何要再写一遍呢?其实也是为了加深本身的印象,巩固本身的基础html (主要是不少文章没有写出来我想知道的东西!!!​!!!!)java ...

  6. Java 集合系列(2): ArrayList源码深入解析和使用示例

    戳上面的蓝字关注我们哦! 精彩内容 精选java等全套视频教程 精选java电子图书 大数据视频教程精选 java项目练习精选 概要 上一章,我们学习了Collection的架构.这一章开始,我们对C ...

  7. 扩容是元素还是数组_02 数组(附ArrayList源码分析)

    定义 用一组连续的内存空间存储一组具有相同类型的数据的线性表数据结构. 优势 支持通过下标快速的随机访问数据,时间复杂度为O(1). 劣势 通常情况下,插入和删除效率低下,每次操作后,需要进行后续元素 ...

  8. 增加数组下标_数组以及ArrayList源码解析

    点击上方"码之初"关注,···选择"设为星标" 与精品技术文章不期而遇 前言 前一篇我们对数据结构有了个整体的概念上的了解,没看过的小伙伴们可以看我的上篇文章: ...

  9. 面试官系统精讲Java源码及大厂真题 - 05 ArrayList 源码解析和设计思路

    05 ArrayList 源码解析和设计思路 耐心和恒心总会得到报酬的. --爱因斯坦 引导语 ArrayList 我们几乎每天都会使用到,但真正面试的时候,发现还是有不少人对源码细节说不清楚,给面试 ...

最新文章

  1. 深度学习模型之各种caffe版本(Linux和windows)的网址
  2. thinkphp字符截取函数msubstr()
  3. (String)、toString、String.valueOf的区别
  4. CentOS 6.2 本地安装YUM
  5. Musik音乐社区整套UI网站模板
  6. abaqus实例手册_ABAQUS_6.10例子问题手册(目录)
  7. 关于JS中一些重要的api实现,巩固你的原生JS功底
  8. linux mint php mysql_Installing LAMP (Linux, Apache, MySQL and PHP) On Linux Mint
  9. 基于Linux下的Nand (Nor) Flash读写速度测试
  10. c语言 switch语句实例,C语言switch语句
  11. 系统思考:智猪博弈(变革)
  12. 简易网页(HTML)
  13. 【iOS】AFNetworking
  14. 二层技术——点对点协议ppp以及NBMA网络MGRE的tunnel隧道技术以及二层综合实验
  15. 命令行创建文件和文件夹
  16. 如何让人机对话更自然?
  17. 18年春季第一题 PAT甲级 1144 The Missing Number (20分) 上限感很重要
  18. 两性离子洗涤剂的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  19. 可编程接口芯片之-----8255A
  20. 分享154个ASP源码,总有一款适合您

热门文章

  1. 爬虫实战——起点中文网小说的爬取
  2. 一行行的代码解密马尔可夫链
  3. CSU-ACM2019寒假训练1-E - 可能简单题
  4. 使用Vlookup筛选数据
  5. 【护眼阅读】PC端通过主流常用浏览器打开本地WEB页面阅读本地TXT小说
  6. FPGA秋招面试手撕代码20+
  7. 把一个用阿拉伯数字表示的正整数转换成汉字大写表示
  8. 7-2 jmu-Java-03面向对象-06-继承覆盖综合练习-Person、Student、Employee、Company (15分)
  9. 在Windows上使用EDA软件——利用WSL安装IC618、SPECTRE181
  10. Python学习笔记 | opencv图像处理(一)