专栏名称: 说说Java那些事儿
Java本简单,不要把它搞复杂了。知乎专栏:Java那些事儿的姊妹篇。
目录
相关文章推荐
Java编程精选  ·  别再使用 ... ·  11 小时前  
芋道源码  ·  线上问题排查指南 ·  2 天前  
芋道源码  ·  全表update的正确姿势 ·  3 天前  
芋道源码  ·  一种简化操作日志记录的方案) ·  4 天前  
芋道源码  ·  一文讲清各种场景下 Git 如何回退 ·  4 天前  
51好读  ›  专栏  ›  说说Java那些事儿

ArrayList底层数组扩容原理

说说Java那些事儿  · 公众号  · Java  · 2017-09-09 08:55

正文

ArrayList部分一共五篇文章了,并且引入了时间复杂度来分析,强烈建议大家一定要按顺序阅读,本文是第二篇

再次强调,ArrayList是一个普通的类,如果我们开心,可以自己写一个

ArrayList初始化 一文发表后,评论区有人问如下问题。

我们先回顾一下之前的所说过的数组,话不多说,上代码:

老规则,我们继续画一画,加深一下印象,上图:

这个图我们去掉了ArrayList初始化 一文图里那些无用的细节(方法区,常量池等),方便大家看起来清晰,我们用eclipse的debug功能看一下,看是否与我们图上画的一致

再看一下执行结果,也在我们期望中。

好,我们改一下代码,再往数组里加添加一个叫“周八”的person对象

执行一下

看到了传说的中数组下标越界异常。在Java中,数组一但在堆内存中创建,长度是固定的。

既然是固定的,那我们要往数组里加一个“周八”用户怎么办?没办法,只能重新new长一点的新的数组,把原来数组的元素复制过去,好吧,开始写代码吧,相信大家都会写

把老数组的元素循环一下,赋值给新的数组,很简单也很清晰。debug看一下

“周八”已经有了。以上代码虽然简单,但还不是最优雅的,老鸟一般会这么写,该段代码执行结果和上面那段代码一样。

再画个图加深一下印象吧:

此图已用尽我洪荒之力,希望大家以后多想想对象在堆内存中的样子。不枉我一片苦心呀。
看到System.arraycopy()方法是不是似曾相识呢?我们在ArrayList初始化一文中提了一下,相信看到这里,大家都知道ArrayList里的底层数组扩容是怎么实现的了吧。在ArrayList初始化 一文中,我们知道当ArrayList如果不指定构造个数的话,第一次往里面添加元素时底层数组会初始化一个长度为10的数组,我们再回顾一下昨天的源码,再来看一下ArrayList里的源码,当添加第11个元素时

再看grow()方法

这儿有一段代码:int newCapacity = oldCapacity + (oldCapacity >> 1),>>是移位运算符,相当于int newCapacity = oldCapacity + (oldCapacity/2),但性能会好一些。

本文开始那个问题,到这儿就解决了,这就是数组的扩容,一般是oldCapacity + (oldCapacity >> 1),相当于扩容1.5倍。

看到这里,相信在以后的面试中,面试官再问数组和ArrayLIst的区别的时候,大家应该有了自己的理解,而不是去背面试题了。

ArrayList还提供了其它构造方法,我们顺便来看一下。

我们再看一下源码,好简单:

当我们在写代码过程中,如果我们大概知道元素的个数,比如一个班级大概有40-50人,我们优先考虑List list2 = new ArrayList<>(50)以指定个数的方式去构造,这样可以避免底层数组的多次拷贝,进而提高程序性能。

看完本文有收获?请转发分享给更多人

长按识别二维码关注


上一篇:ArrayList初始化



推荐文章
芋道源码  ·  线上问题排查指南
2 天前
芋道源码  ·  全表update的正确姿势
3 天前
芋道源码  ·  一种简化操作日志记录的方案)
4 天前
芋道源码  ·  一文讲清各种场景下 Git 如何回退
4 天前
肌肉男训练营  ·  如何更加快速的增长肌肉?原因是…
7 年前
老北京城  ·  首都拿走!北京请留下!!
7 年前
广东配音最前线  ·  人才发明洗头神器,有咗距方便到不得了!
7 年前
小学生作文  ·  伊索寓言:下金蛋的鹅
7 年前