Java数据结构-ArrayList最细致的解析笔记
ArrayList是一个类,这个类有一个数组参数elementData,ArrayList集合中的元素正是保存在这个数组中,它继承了数组查询的高性能,参考第3篇。ArrayList还封装了很多方法,便于对数组中的数据进行操作处理,其中就包括上一篇说的扩容,建议先理解第3篇数组。
扩容原理
在eclipse中调试以下代码,如下设置四个断点,打开调试视图。
public static void main(String[] args) {
List list = new ArrayList();
System.out.println("断点1");
list.add(1);
System.out.println("断点2");
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
list.add(8);
list.add(9);
list.add(10);
System.out.println("断点3");
list.add(11);
System.out.println("断点4");
}
断点1:list的数组参数elementData的值为Object[0],表示数组初始长度为0。
断点2:在集合中添加了第一个元素,elementData数组长度变成了10。即初始扩容长度为10。
断点3:在集合中一共添加了10个元素,elementData长度仍然为10,此时无需扩容。
断点4:添加第11个元素,即超出了原数组长度。elementData长度扩容为15,即第二次以后的扩容,长度为原长度的1.5倍。
注意看图,elementData在断点1时标识是29,在断点2和断点3处的标识都是31,而在断点4时标识46,第2篇讲过,这说明elementData引用变量前后一共指向了三个不同的数组对象。也就是说,elementData并没有真正的扩容,而是创建了一个容量更大的数组对象来替代之前的数组,并且复制之前的数组内容。
元素类型Object
第3篇讲过,数组元素的长度必须是一致的。而以上代码中,我添加的都是int类型数据。假如我添加一个long型数据,如下,也是可以的。而int(4字节 )和long(8字节 )的长度是不一样的,这是为什么?
list.add(1);
list.add(1l);
假如声明时使用List,就指定了固定元素类型。而我的代码中并没有使用泛型,所以它的类型可以是任意Object,但不能是基本类型。当添加int元素时,会自动转换为Integer。当添加long元素时,会自动转换为Long。因此,最终list所有的元素类型都是引用类型(4字节),长度相同,这是实现数组高性能查询所必需的。以后讲其他集合的元素类型时,也和ArrayList是一样的原理,不再解释。
在尾部添加
第3篇在数组中添加了5亿个元素,很快就执行完成。假如用同样的方法在ArrayList中添加5亿元素会怎么样?
int size=500000000;
List list = new ArrayList();
long t1 = System.currentTimeMillis();
for(int i=0;i<size;i++){
list.add(i);
}
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);
运行结果:内存溢出
一直运行了n分钟没有结果,最终报错内存溢出。因为在这个过程中,会不断的扩容,不断的创建新数组对象,最终把内存撑爆。要解决这个问题,可以在创建ArrayList时传入一个int参数,根据参数值会直接初始一个较大的数组,就不用再频繁的扩容了。注意:如果初始数组太大又不使用,也会让费内存空间。修改代码,将new ArrayList()改成new ArrayList(size)
List list = new ArrayList(size);
只是这样做还不够,因为上面说了,list.add(i)实际上是创建了5亿个对象,数据量太大内存仍然不足。再次修改添加代码,将list.add(i)改成list.add(1),1会转换成new Integer(1),5亿个new Integer(1)仍然是5亿个对象。但是java对一些对象做了缓存,其中包括new Integer(0至127),以后会讲。现在只需知道,i改成1后只会有一个new Integer(1)对象,而不会创建5亿个对象。之后文章都会使用1作为集合参数,不再解释。修改代码如下 ,再次运行
list.add(1);
耗时:1080毫秒
add()方法默认是在尾部添加数据,ArrayList的size可以帮助数组瞬间完成定位,然后直接添加,所以这样的性能是很高的。
在指定位置添加
list.add(int index,E element)方法是在位置index处添加,如下
int size=500000000;
List list = new ArrayList(size);
long t1 = System.currentTimeMillis();
for(int i=0;i<size;i++){
list.add(0,1);
}
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);
耗时:无限
上图可以看出,向指定位置0插入元素时,其后面的所有元素都要一个个的向后移动,即每添加一个元素要移动n次元素。虽然没有创建对象,不会内存溢出,但是时间性能实在太低。
删除的性能
和添加同理,在尾部删除性能很高。但在指定位置删除也存在性能问题,需要把后面元素一个一个的往前移。
特性
有序列表:集合中的元素按照添加顺序排列,先添加进集合的排在前面,后添加的排在后面。
底层就是数组:操作尾部数据时,其性能是最高的。操作越靠前的数据,性能越低。
封装了数组:操作更简便,代码可读性更高。但是也封装了额外操作,比如安全检查,数组是否越界等,这也带来一些性能开销,所以ArrayList性能会比数组稍稍低那么一点点。
应用场景
做普通项目时,对性能没有那么严格的要求,如果想要快速开发,使用封装过的ArrayList是第一选择。
关于从指定位置添加和删除,是ArrayList的性能缺陷。我们要做的是将其优点发挥到其擅长的场景,将其不擅长的场景交给其他数据结构来处理,扬长避短。后续要介绍的集合都是一样,没有哪一种结构是完美的,只有其最适合哪种场景。
百人微信讨论群,如果群二维码失效请加微信拉你入群 shengruxiahua3596 ,加微信请备注 程序员-java
Java数据结构-ArrayList最细致的解析笔记的更多相关文章
- Java数据结构ArrayList
Java数据结构ArrayList /** * <html> * <body> * <P> Copyright JasonInternational</p&g ...
- JAVA数据结构--ArrayList动态数组
在计算机科学中,动态数组,可扩展数组,可调整数组,动态表,可变数组或数组列表是一种随机存取可变大小列表数据结构,允许添加或删除元素.它提供许多现代主流编程语言的标准库.动态数组克服了静态数组的限制,静 ...
- Java数据结构之表的增删对比---ArrayList与LinkedList之一
一.Java_Collections表的实现 与c不同Java已经实现并封装了现成的表数据结构,顺序表以及链表. 1.ArrayList是基于数组的实现,因此具有的特点是:1.有索引值方便查找,对于g ...
- 【Java数据结构学习笔记之一】线性表的存储结构及其代码实现
应用程序后在那个的数据大致有四种基本的逻辑结构: 集合:数据元素之间只有"同属于一个集合"的关系 线性结构:数据元素之间存在一个对一个的关系 树形结构:数据元素之间存在一个对多个关 ...
- Java集合-ArrayList源码解析-JDK1.8
◆ ArrayList简介 ◆ ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAcc ...
- 词典的实现(3)--使用JAVA类库ArrayList实现Map数据结构
1,在词典的实现(2)-借助顺序表(数组)实现词典文章中使用了自定义的数组代替ArrayList,并实现了Map数据结构的基本功能.而借助JAVA类库ArrayList类的一些方法可以更加容易地实现M ...
- Java 的 ArrayList 的底层数据结构
1. 数据结构--ArrayList源码摘要 ublic class ArrayList<E> extends AbstractList<E> implements List& ...
- Java基础知识强化之集合框架笔记70:模拟斗地主洗牌和发牌(ArrayList)
1. 模拟斗地主洗牌和发牌 分析: A:创建一个牌盒 B:装牌 C:洗牌 D:发牌 E:看牌 2. 代码实现: package cn.itcast_03; im ...
- Java基础知识强化之集合框架笔记69:Collections类之ArrayList存储自自定义对象并排序的案例
1. ArrayList存储自自定义对象并排序的案例: ArrayList存储自自定义对象,并使用Collections对ArrayList存储基本包装类的元素排序. 2. 代码实现: (1)Stud ...
随机推荐
- MySQL数据库中文乱码问题
mysql> select * from books; +-----+---------------------------------+---------+-------------+---- ...
- 使用electron开发桌面级小程序自动部署系统
那一天我二十一岁,在我一生的黄金时代,我有好多奢望.我想爱,想吃,还想在一瞬间变成天上半明半暗的云,后来我才知道,生活就是个缓慢受锤的过程,人一天天老下去,奢望也一天天消逝,最后变得像挨了锤的牛一样. ...
- [Gamma阶段]第三次Scrum Meeting
Scrum Meeting博客目录 [Gamma阶段]第三次Scrum Meeting 基本信息 名称 时间 地点 时长 第三次Scrum Meeting 19/05/29 大运村寝室6楼 30min ...
- Gamma阶段第五次scrum meeting
每日任务内容 队员 昨日完成任务 明日要完成的任务 张圆宁 #91 用户体验与优化https://github.com/rRetr0Git/rateMyCourse/issues/91(持续完成) # ...
- fastjson WriteClassName,Double类型不打3.3D
方式一: public class SerializeConfigX extends SerializeConfig { public SerializeConfigX() { put(Double. ...
- 解决 android push framework.jar 不生效的问题
. . . . . 在 Android 采用 ART 虚拟机后,为了提高运行时效率,在编译期间会将 jar 包中的 dex 文件编译为 odex.vdex 等文件.而这些文件并不存放在 framewo ...
- iOS App转让、转移、迁移(App transfer) -- 仅需四步
当需要将某个 App 出售给其他开发人员,或想要将其移至其他 App Store Connect 组织,则您需要转让该 App.您无需将 App 从 App Store 下架,即可将其所有权转让给另一 ...
- SAP翔子_增强篇索引
序号 描述 SAP翔子_增强篇0 增强篇0 SAP的多种增强方式 SAP翔子_增强篇1 增强篇1 PO保存增强 SAP翔子_增强篇2 增强篇2 生产订单屏幕增强 SAP翔子_增强篇3 增强篇3 SAP ...
- EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器web前端:vue组件之间的传值,父组件向子组件传值
前端方面,EasyDSS流媒体服务器与EasyNVR有着根本的不同.EasyNVR使用的是传统的js来进行开发,而EasyDSS使用的是webpack+vue来进行开发的,了解vue+webpack的 ...
- The last packet successfully received from the server was 1,480 milliseconds ago.
场景:一个上传接口,需要上传几十M的文件,文件中包含10几W的数据,然后对10+W的数据进行同步批量插入,每次批量插入1W.最后返回结果. 项目上线一段时间后,上传接口出现问题,数据库用的MySQL5 ...