顺序线性表 ---- ArrayList 源码解析及实现原理分析
原创播客,如需转载请注明出处。原文地址:http://www.cnblogs.com/crawl/p/7738888.html
----------------------------------------------------------------------------------------------------------------------------------------------------------
笔记中提供了大量的代码示例,需要说明的是,大部分代码示例都是本人所敲代码并进行测试,源码已经标注出,不足之处,请大家指正~
本博客中所有言论仅代表博主本人观点,若有疑惑或者需要本系列分享中的资料工具,敬请联系 qingqing_crawl@163.com
-----------------------------------------------------------------------------------------------------------------------------------------------------------
前言:
前一段时间在大学课堂上学习了 c++ 版的数据结构,虽然考过了,但是感觉学的不扎实,不深入。尤其是楼主主要是 Java 方向的,所以一直想着再学习来一遍,一边学习数据结构,一边看着 jdk 源码,提升一下自己的内功。
数据结构的开篇当然要拿顺序线性表开刀了。当然这一部分自认为还是比较简单,直接来拿 ArrayList 说事。
一、ArrayList 概述
ArrayList是 List 接口的可变数组的实现。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。
每个 ArrayList 实例都有一个容量,该容量是指用来存储列表元素的数组的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造 ArrayList 时指定其容量。
二、ArrayList 源码解析
值的注意的是,对于 ArrayList 来说,它实现了 List 接口,底层是使用数组来实现的,所以对 ArrayList 的操作,实际上就是对数组的操作。下面我们看一看,ArrayList 到底是如何实现的?
1.底层使用数组实现:
transient Object[] elementData;
2. 构造方法:ArrayList 实现了三种形式的构造器,可以构造一个空的列表,也可以构造一个由我们指定初始容量的空列表,还可以构造一个包含 Collection
的元素的非空列表
源码:
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}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)elementData = Arrays.copyOf(elementData, size, Object[].class);} else {// replace with empty array.this.elementData = EMPTY_ELEMENTDATA;}}
3. set(int index, E element) 和 add(E e),这两个方法比较简单,简单说明一下即可。
set(int index, E element) 可以用指定的元素替代列表中指定位置上的元素,并返回被替代了的元素,第二行的 rangeCheck() 方法是对传入的 index 进行范围的校验,很简单,不再说明。
public E set(int index, E element) {rangeCheck(index);E oldValue = elementData(index);elementData[index] = element;return oldValue; }
add(E e) 方法,将指定的元素添加到列表的末尾,第 2 行做的是检查添加后是否超过了数组的长度,如果超过了则为数组扩容,然后再添加。
public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true; }
4. add(int index, E element) 将指定的元素插入到列表的指定位置
解析:第 2 行的方法是对传入的 index 进行校验,判断其 index > size || index < 0,若满足此条件,则抛异常:IndexOutOfBoundsException(outOfBoundsMsg(index))。
第 3 行的 ensureCapacityInternal() 方法是检查添加后是否超过了数组的长度,如果超过了则为数组扩容。
第 5 行为主要操作,是将 elementData 数组中的从 index 开始,长度为 size - index 的元素拷贝到 index + 1 的位置上,即将这些元素后移一位。然后第 7 行将空缺出来的 index 位置上的元素赋值为出入的 element。
1 public void add(int index, E element) { 2 rangeCheckForAdd(index); 3 4 ensureCapacityInternal(size + 1); // Increments modCount!! 5 System.arraycopy(elementData, index, elementData, index + 1, 6 size - index); 7 elementData[index] = element; 8 size++; 9 }
5. addAll(Collection<? extends E> c) 方法,将该 collection 中的所有元素添加到此列表的尾部,此方法不难理解,不再详解。
public boolean addAll(Collection<? extends E> c) {Object[] a = c.toArray();int numNew = a.length;ensureCapacityInternal(size + numNew); // Increments modCountSystem.arraycopy(a, 0, elementData, size, numNew);size += numNew;return numNew != 0;}
6.addAll(int index, Collection<? extends E> c) :从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。此方法与之前介绍的 add(int index, E element) 几乎一样,add(int index, E element) 方法已经详细介绍过了,也不再赘述。
1 public boolean addAll(int index, Collection<? extends E> c) { 2 rangeCheckForAdd(index); 3 4 Object[] a = c.toArray(); 5 int numNew = a.length; 6 ensureCapacityInternal(size + numNew); // Increments modCount 7 8 int numMoved = size - index; 9 if (numMoved > 0) 10 System.arraycopy(elementData, index, elementData, index + numNew, 11 numMoved); 12 13 System.arraycopy(a, 0, elementData, index, numNew); 14 size += numNew; 15 return numNew != 0; 16 }
7. get(int index):返回此列表中指定位置上的元素。 同样先校验 index ,然后直接获取即可。
1 public E get(int index) { 2 rangeCheck(index); 3 4 return elementData(index); 5 }
8. remove(int index):移除此列表中指定位置上的元素。
解析:首先在第 2 行还是先校验传入 index 是否在正常的范围内。
第 5 行取出 index 位置的元素。
第 7 行定义了一个 munMoved = size - index - 1,对应为要删除的这个 index 位置的元素后面元素的个数,若 index 位置后面还有元素,就将 elementData 从 index + 1 位置开始的 numMoved 个元素复制到 index 位置,即让 index 后面的元素向前移了一位,这样就将 index 位置的元素删除了。
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); 11 elementData[--size] = null; // clear to let GC do its work 12 13 return oldValue; 14 }
为了让大家更好的理解,LZ 画了一个示意图供大家参考:
9. remove(Object o):移除此列表中首次出现的指定元素(如果存在)。这是因为 ArrayList 中允许存放重复的元素。
解析:值的注意的是 ArrayList 中允许存放 null 值,所以此操作要分两种情况来完成。
而第 5 行和第 11 行的 fastRemove(int index) 方法,类似于 remove(int index) 方法,前面已经做了详细的讲解。
1 public boolean remove(Object o) { 2 if (o == null) { 3 for (int index = 0; index < size; index++) 4 if (elementData[index] == null) { 5 fastRemove(index); 6 return true; 7 } 8 } else { 9 for (int index = 0; index < size; index++) 10 if (o.equals(elementData[index])) { 11 fastRemove(index); 12 return true; 13 } 14 } 15 return false; 16 }
总结:关于 ArrayList 的源码解析和实现原理 LZ 先介绍到这里,都是挑选常用的方法来介绍的,欢迎大家一块学习,讨论交流。后续的关于数据结构的知识 LZ 还会持续更新~~
转载于:https://www.cnblogs.com/crawl/p/7738888.html
顺序线性表 ---- ArrayList 源码解析及实现原理分析相关推荐
- 增加数组下标_数组以及ArrayList源码解析
点击上方"码之初"关注,···选择"设为星标" 与精品技术文章不期而遇 前言 前一篇我们对数据结构有了个整体的概念上的了解,没看过的小伙伴们可以看我的上篇文章: ...
- ArrayList源码解析与相关知识点
ArrayList源码解析于相关知识点(超级详细) 文章目录 ArrayList源码解析于相关知识点(超级详细) ArrayList的继承关系 Serializable标记接口 Cloneable标记 ...
- 面试官系统精讲Java源码及大厂真题 - 05 ArrayList 源码解析和设计思路
05 ArrayList 源码解析和设计思路 耐心和恒心总会得到报酬的. --爱因斯坦 引导语 ArrayList 我们几乎每天都会使用到,但真正面试的时候,发现还是有不少人对源码细节说不清楚,给面试 ...
- 老李推荐:第5章5节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 获取系统服务引用 1...
老李推荐:第5章5节<MonkeyRunner源码剖析>Monkey原理分析-启动运行: 获取系统服务引用 上一节我们描述了monkey的命令处理入口函数run是如何调用optionPro ...
- 老李推荐:第6章1节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览 1...
老李推荐:第6章1节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览 在上一章中我们有简要的介绍了事件源是怎么一回事,但是并没有进行详细的描述.那么往下的这几个 ...
- 老李推荐:第6章6节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览-命令队列...
老李推荐:第6章6节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览-命令队列 事件源在获得字串命令并把它翻译成对应的MonkeyEvent事件后,会把这些事件 ...
- 安卓开发者必看:Android的数据结构与算法——ArrayList源码解析
作者:JerryloveEmily 原文链接:https://www.jianshu.com/p/159426e2aaf6 文章有点长,比较啰嗦,请耐心看完! 一.概述 首先得明白ArrayList在 ...
- Android的数据结构与算法----ArrayList源码解析
转载请标明出处: http://blog.csdn.net/abren32/article/details/56669369 本文出自JerryloveEmily的博客 文章有点长,比较啰嗦,请耐心看 ...
- 面试必备:ArrayList源码解析(JDK8)
概述 很久没有写博客了,准确的说17年以来写博客的频率降低到一个不忍直视的水平.这个真不怪我,给大家解释一下. 一是自从做了leader,整天各种事,开会,过需求,无限循环.心很累,时间也被无线压榨 ...
最新文章
- 华为云力推“普惠AI”,EI智能体正在落地行业
- spire.doc 转html,c# html 转Word--Spire.Doc
- nginx忽略favicon.ico日志
- 30 分钟让你掌握 Git 的黑魔法
- boot.asm文件注释
- C 中的内存操作函数-memcpy 等(to be continued)
- pandas.get_dummies
- Fastdata极数:2021年中国互联网基金投资用户报告
- 机器学习实战8-sklearn降维(PCA/LLE)
- 人机交互界面设计大作业_为什么说大多数UI设计、大数据、人工智能等培训班不靠谱?...
- 张季跃 201771010139《面向对象程序设计(java)》第十三周学习总结
- java线程的状态改变(练习)
- 【转载】2012年七个免费ASP空间分享-支持ASP、ASP.NET的空间
- 【计算机网络】3-20假定1km长的CSMA/CD网络的数据率为1Gbit/s。设信号在网络上的传播速率为200000 km/s。求能够使用此协议的最短帧长。
- 物联网毕设 -- ESP32-CAN加摄像头传输图像,STM32驱动小车自动避障图像采集并显示到Android端
- 内联函数let、also、with、run、apply的用法
- markdown编辑器的基本使用
- 苹果手机密码设置在哪里_sim卡密码设置在哪里-sim卡密码设置介绍
- 论文 | 科研软件 —— Microsoft VisioPro 2019安装及注册教程
- 进程间通信和线程间通信
热门文章
- mybatis日期范围查询_15. Django 2.1.7 模型 条件查询、模糊查询、空查询、比较查询、范围查询、日期查询...
- 环形队列的输出_循环队列的基本操作详细讲解
- label mpchart 饼图_运用matplotlib绘制折线图、散点图、饼图、柱形图的定义代码以及案例详解...
- JavaEE编码规范
- c语言编译软件容错策略,软件容错方法之——软件冗余
- oracle+rac+导出,Oracle RAC数据泵导出问题处理
- hashmap头插法和尾插法区别_Java程序员必知:HashMap进行put操作会不会引起死循
- videojs默认显示controls 按钮功能失效_一文看懂Yearning SQL审核平台功能模块设计...
- 计算机会计系统审计的内容包括什么,会计电算化系统审计.docx
- android调用日历库,Android学习教程之日历库使用(15)