ArrayList源码解析

因为是楼主第一篇博客,楼主又是菜鸡,所以决定挑个软柿子捏一捏,瞅一瞅ArrayList。
简介:
楼主是jdk1.8,大家看的时候注意下版本。ArrayList的底层是数组,并且可以动态扩容的。

继承关系:
在这里插入图片描述实现了四个接口,一个抽象类。四个接口没啥好说的。

属性:
在这里插入图片描述东西比较少,并且也不复杂。

构造方法:
在这里插入图片描述
上面的两个构造方法大家应该都很熟悉,下面有个不太常见的构造方法,我们仔细看一下。
在这里插入图片描述
Arrays.copyOf和c.toArray()最后调用的下面的copyOf这个方法在这里插入图片描述if (elementData.getClass() != Object[].class)这一步的判断特地拿出来说一下,虽然上面的elementData = c.toArray()基本上得到的大概率是Object类型,但是这里的判断还是看不懂,既然需要一个Object类型的数组,为啥第一次调的时候不给定Object类型呢?第二次再去拷贝一遍?大家谁知道可以留下言指点一下。
public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length)
这个方法的大概意思如下:
在这里插入图片描述其实就是浅拷贝一个新的数组,指定了老数组从哪开始(srcPos),拷贝多少个(length),新数组从哪开始(destPos)。
因为是native方法,底层是c写的,看不见。楼主也没去找具体的源码,就简单用java实现下伪代码:
在这里插入图片描述可以看到,要是ArrayList扩容的次数过多,肯定是极其影响性能的,所以用ArrayList还是要尽量给定容量。

下面看一下ArrayList的方法,这里只分析一下几个常用的方法。
add(E e)方法:
在这里插入图片描述也比较简单,就是判断一下当前数组的元素的个数加1,是否会大于容量,大于就要进行扩容,这样的add不用扩容的话其实也很快。

扩容grow方法:
在这里插入图片描述扩容方法也不复杂,大概就是扩容1.5倍,然后重新copy一份新的数组。顺便说一下Arrays.copyOf这个方法,是浅拷贝。
这里大概捋一下浅拷贝的意思:
1:当数据类型是基本数据类型,浅拷贝会进行值传递,也就是复制一份新的数据,改变其中一个对象,不会影响另一个对象。
2:当数据类型是引用数据类型,浅拷贝会进行引用传递,也就是将原对象的引用值(内存地址)复制给新对象,说白了就是2个对象指向同一块内存地址,所以改变其中一个对象,会影响另一个对象。
下面我们简单验证一下:
在这里插入图片描述这里首先用基本数据类型测试一下,发现是不会相互影响的。
在这里插入图片描述这是引用数据类型的测试,发现改变一个对象是会影响另一个,因为他们同时指向的同一块内存地址。

add(int index, E element):
在这里插入图片描述
if (index > size || index < 0)这句话的意思是个人的想法,不知道对不对。
System.arraycopy(elementData, index, elementData, index + 1, size - index)到最后仍然调用的nactive的public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length)方法。
这个方法的意思其实上面说过了,只不过这里的新老数组是同一个,再描述一下:
在这里插入图片描述
下面再看下伪代码:
在这里插入图片描述可以看到,指定下标的add确实很慢。

remove(int index):
在这里插入图片描述
System.arraycopy(elementData, index+1, elementData, index, numMoved)大概意思如下图:
在这里插入图片描述
下面再看下伪代码:
在这里插入图片描述可以看到,指定下标的remove确实很慢。

remove(Object o):
在这里插入图片描述其实2种删除方法差不多,只不过下面多了一步,先遍历找到下标,然后再删,,效率也很低。

set(int index, E element):
在这里插入图片描述更新超级简单,就是检查下,重新赋值。

get(int index):
在这里插入图片描述查询也没啥好说的,可以看到查询确实快,直接根据下标查找的。

contains(Object o):
在这里插入图片描述也很简单,遍历判断,但是这种遍历查找相当于线性查找,效率最低。

modCount:
相信大家多次看到过这个参数,下面来看下这个参数有啥用。其实直接操作ArrayList是没有的,但是我们遍历ArrayList的时候,很多人要用到list.iterator()迭代遍历,这时候就有用了。
相信很多人这么写过:
在这里插入图片描述迭代遍历,让我们来看下迭代的源码:
在这里插入图片描述
在这里插入图片描述这个modCount是为了保证迭代的时候没有别的线程操作当前ArrayList,保证准确性的。

第一篇文章终于结束了,下篇分析LinkedList(不知道还有没有…)。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值