《数据结构》第九篇、java中ArrayList源码解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/JerryWu145/article/details/79965306
机械师2.jpeg
机械师2.jpeg

引言

如题,为什么今天要给大家介绍java的中的ArrayList的源码呢?因为我毕竟是一个android开发工程师,不能一直给大家通过c语言讲解数据结构呀,java中也存在数据结构知识呢,我们的第7篇文章中介绍了下线性表中的顺序表,今天我们就来介绍一下java中的“顺序表的应用”,即ArrayList。

那大家大概猜到了,既然我说ArrayList是顺序表在Java中的应用,那么他内部是不是通过数组实现的呢?
你猜对了,就是通过数组实现的。

大致看下源码

我们来大致看下ArrayList的源码,这里我是通过Android studio看的,所以源码应该和java工程师用eclipse看的不太一样(有一些常量值可能不太一样),但是大体逻辑是类似的。
我贴张图,大家来感受一下:


Arraylist源码.png
Arraylist源码.png

我们看到,Arraylist源码有1476行,感觉是比较复杂的,而我们感兴趣的无非就是那么几种:

创建

添加元素

删除元素

清空列表

转成数组

所以,本篇文章就先从这几点入手,如果后续有朋友需要对其他操作解析讲解的话,可以私信我,我会再帮你分析一下的。

ArrayList的创建

先来看图


ArrayList创建.png
ArrayList创建.png

ArrayList创建提供了三个构造方法:

  • 带int 参数的构造方法
  • 无参构造方法
  • 带集合参数的构造方法
    我们先来看第一个

1、带int 参数的构造方法

带int参数的构造方法.png
带int参数的构造方法.png

其实大家看上方的英文注释就能明白一二了:
“这个构造方法指定了一个固定的容量,使用参数去设置Arraylist的容量大小”
所以说我们就可以这样去创建ArrayList:
ArrayList<String> list=new ArrayList<String>(5);
通过指定固定的大小去创建ArrayList。

但是,这样做就能够真的让ArrayList的容量是5了吗?我们来分析下


构造方法1.png
构造方法1.png

需要参考的值


构造方法1值.png
构造方法1值.png

细看源码,是不是恍然大悟,原来集合内部有一个“内部数组"
elementData

看我们的注释,我们似乎猜对了,只要我们传入的容量值大于0,就能够设定固定容量的集合,如果传入的等于0,就直接用的是一个空的数组,如果小于0,则直接报错。


2、无参的构造方法

我们看过了有参的构造方法,其实再看无参的构造方法就觉得简单多了,来看一下吧:


构造方法2.png
构造方法2.png

需要参考的值


构造方法2值.png
构造方法2值.png

”即复用了一个空的数组,这个数组和方法一种的数组是区分开的,区分开的目的是在进行第一个元素添加的时候计算需要扩充多大的容量。“
ok,其实我们常用的也就这样,直接new 出来
ArrayList<String> list=new ArrayList<String>();
所以我们这样写,跟我们直接指定大小容量的写现在看看应该没什么区别。


3、带collection参数的构造方法

构造方法三.png
构造方法三.png

"参数是一个带泛型的集合,该构造方法将会把参数中的元素放置到新创建的集合中去"
即通过这个方法我们可以获得跟传入集合一样的集合,里面的元素都是一模一样的,就是创建了个副本
解释一下
构造方法二解析.png
构造方法二解析.png

我们使用的时候就可以这样
构造方法3使用.png
构造方法3使用.png

得到list1的副本~~


ok,ArrayList的创建就先到这里,接下来我们看看ArrayList元素的添加

添加元素

两个.png
两个.png

元素添加有两个方法,我们先看第一个

1、添加元素到结尾方法

元素添加1.png
元素添加1.png

”将元素添加到集合的最后位置“
解释一下

添加元素解释.png
添加元素解释.png

我们看到,首先在添加元素的时候,做了一个扩容的操作我们点击进去看一下
扩容.png
扩容.png

我们看一下参考值
扩容参考值.png
扩容参考值.png

接着,在扩容方法中又调用了一个”明确扩容的方法“:
明确扩容.png
明确扩容.png

紧接着,又调用了下grow方法,到这里grow才是真正的扩容方法了


真正的扩容方法.png
真正的扩容方法.png

在扩容方法的最后,我们看到了数组复制的逻辑:


数组复制.png
数组复制.png

但是我们接着点进去,看看真正的数组复制的方法
复制数组方法2.png
复制数组方法2.png

在进入System.arraycopy方法


真正数组复制的方法.png
真正数组复制的方法.png

因为add方法套的比较深了一点点,所以我画了张图,来看一下


java add流程.png
java add流程.png

应该对你理解有点帮助吧~~

最终


把要插入元素添加到结尾.png
把要插入元素添加到结尾.png

2、添加元素到指定位置

添加元素到指定位置.png
添加元素到指定位置.png

“把指定元素添加到集合的指定位置(将要插入元素位置之后的元素向后移动一个单位,然后将元素插入到中间)”
解释一下
插入元素到指定位置.png
插入元素到指定位置.png

我们看到,
1、首先做了一个参数校验,不允许插入索引大于集合的容量或者小于零,否则报数组越界异常。
2、跟上方的add(E element)方法一致,做扩容和复制的操作
3、这一点和add(E element)方法不一致,且比较关键,他的作用是将要插入元素位置之后的元素向后移动一个单位
4、在要插入的位置替换成要插入元素的值
5、增加集合长度


删除元素

删除元素两种.png
删除元素两种.png

即一个是根据索引删除,一个是根据元素值删除
我们先来看根据索引删除的

1、根据索引删除元素

我们先看图

删除元素01.png
删除元素01.png

“将指定位置的元素删除,并且把删除位置后边的元素向左移动”
解释一下:
根据索引删除元素解释.png
根据索引删除元素解释.png

比添加元素简单,因为不需要考虑到扩容问题
接着看

2、根据元素值删除元素

看源码:


根据元素值删除元素.png
根据元素值删除元素.png

“将第一次出现的对应元素值的元素删除掉,如果集合中没有这个元素值,集合将不会有所改变”
解释一下啦

根据元素值删除解释.png
根据元素值删除解释.png

我们看到上边有一个fastRemove方法,我们来看一下:
fastremove.png
fastremove.png

我们看到,这个fastRemove方法和我们的根据索引删除方法很像
1、modCount++是计数单位,我们不做考虑
2、int numMoved=size-index-1;计算要移动的元素数量
3、移动元素
4、将结尾元素置为空。
所以其实根据元素值删除元素也是依据根据索引删除的。

清空集合

就是我们常用的clear方法,我们来看一下

清空集合.png
清空集合.png

"移除集合中的所有元素,当处理结束后,这个集合就是一个空集合"
我们看步骤:
1、modCount++不需要考虑,跳过
2、循环数组,将每个元素置为空
3、改变集合长度为0
so easy!

转为数组

即我们常用的toArray方法


toarray.png
toarray.png

我们看到,有两个方法,一个无参,一个有参

1、无参toArray方法

无参toArray.png
无参toArray.png

“根据集合的顺序,返回一个包含所有元素的集合”
我们看到上边ArrayCopy应该就能想到上方我们添加元素那的操作了吧。操作是一致的,就是将集合中的数组的所有元素都复制到另外一个数组中,并且返回。
点进去看看:
toarray进入1.png
toarray进入1.png

toarray进入2.png
toarray进入2.png

就是将原来集合中的数组再进行了一次复制

2、有参toArray方法

有参toArray.png
有参toArray.png

"根据集合的顺序,返回一个包含所有元素的集合,这个集合是自己指定的,如果指定的这个集合有足够的空间,那么如果将所有元素复制进来的话,源集合尾元素将置为空"
解释一下:

有参toArray解释.png
有参toArray解释.png


总结,好了,今天介绍了也不少了,但是还有查找,替换这两个简单的操作还没有讲解到,不过看完今天的介绍,这两个操作对大家来说应该没什么问题了。不过有问题也可以私信我~~

谢谢大家关注~~~么么哒

阅读更多

没有更多推荐了,返回首页