ArrayList理解

本篇文章不定期更新(但是肯定会分析完),不正确的地方还望指出

1.首先最常写的就是new ArrayList();所以我们先来由浅入深,了解一下ArrayList的无参构造器



elementData是用于存放元素的数组

2.常用的方法还有add(E e)


先讲一下大致意义,首先确保容量足够,然后size是指当前容量,将元素存进数组中。

现在来讲一下arrayList的ensureCapacityInternal()。


首先是判断elementData数组是不是刚初始化的,如果是的话,将最小的容量设置为默认容量值10;这一步主要是为了给与最小默认长度为10。然后进入ensureExplicitCapacity()方法,接着进去看。


modCount是指修改的次数,接着进入grow方法。


上面的主要一段话是说

(1)将容量扩充为1.5倍+1

(2)如果新的容量大于了Integer的arrayList的最大容量(Integer.MAX_VALUE - 8),将容量设为最大值

(3)将原来的数组通过util的Arrays.copyOf()方法将引用放入新的数组里。这里需要注意的是,是从第一个位置开始复制到每个位置上面,那么这就是arrayList的添加效率低的问题。

3.紧接着就是get(int index)方法了


首先看方法应该就是先判断是否越界,进去一看果然如此,如果index>=size的话就会抛出IndexOutOfBoundsException异常。

没越界的话就会返回元素

4.接着可以看contains(Object o)方法


进入indexOf(Object o)看,


可以看出,基本是依靠遍历寻找,那么时间复杂度就是O(n)了。这里需要注意的是,调用的是equals()方法,所以需要重写equals(),其实这里我自己写的话,我认为不用判断是否为null,直接写成elementData[i] .equals(o)可能会更加优雅(个人看法,如果不正确的话,望指出。)

5.接着看一下add(int index,E e)方法


(1)首先是确保index<=size

(2)计算是否需要扩容

(3)然后进入arraycopy()方法。这是JDK的native方法。根据实例,分析出,其主要是将index前面位置的数据不变,然后将index位置的数据依次向后移动。然后再在index位置插入数据

6.讲了add的两个方法,就来讲讲为什么其增慢。

(1)正常添加,你可能需要扩容。并且扩容之后需要拷贝数组。

(2)插入的话,你可能要扩容,并且需要移动角标。

(说个题外话,其实当数据量特别大的时候,例如几百万,arrayList的添加速度是快于LinkedList的,这点可以做实验验证)

7.讲一下remove(Object o)方法。


首先,还是先遍历寻找,如果找到的话,进入fastRemove()方法。


首先增加修改次数,然后一样的将数组后面的向前移动。最后将引用指向null,便于gc进行回收

8.接着是remove(int index)方法。返回的是被删除的对象


其实和remove(E e)的方法差不多。

接着补充,对于ArrayList的elementData分析

为什么会是transient修饰呢?因为如果让jvm自行进行序列化的话,那么假设现在只有一个数据,但是数组的长度是10,那么jvm就会序列化10长度的数组,降低了效率,也浪费了空间,因此考虑自己序列化。arrayList可是实现了Serializable接口的,那么这就意味这是可以序列化得,继续寻找,发现了arrayList的两个方法。


先是writeObject方法,就是自己通过对象流的方式写出去,因为arrayList不是线程同步的,所以采用了类似cas算法的方式,确保写出时,是最新的。


然后是readObject这个方法,首先将size读取到,然后确保容量,然后进行for循环赋值。

接下来研究一下重要的东西iterator接口,这是个顶级接口,Collection也是继承与iterator接口的。先讲一下iterator接口的作用,其主要是在遍历的时候用的,也因为list继承于iterator,所以我们可以对其子类使用foreach循环语法糖。

先进入切入点


首先是arraylist的iterator()方法,能够得到一个iterator的实现类Itr,


现在看一下Itr类的拥有的属性和方法


cursor:游标,由于没有赋值,但是是成员变量,默认为0

lastRet:上一个被返回的元素的下标,没有的话,默认-1

expectedModCount:修改次数

接着看,hasNext()方法。


就是一个判断,判断游标的位置和elementData的长度

接着进入next()方法


先大致理一下步骤

(1)检查在iterator过程当中,arrayList是否进行过修改,如果修改过,则会报错。这也就是为什么在遍历过程当中,你不能够使用list的remove(Object)方法,不然那就是报错的原因。


(2)判断游标是否超过数组容量,如果超过了,则会报错。

(3)游标向后移动一格。

(4)返回该元素。

最后看一下Itr的remove()方法。


(1)首先判断是否还有元素。

(2)检验arrayList是否被修改过。

(3)调用arrayList的remove(int index)方法,然后将游标向前移动一格,最重要的是将expectedModCount重新赋值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值