java源码分析_深入分析java集合ArrayList(源码分析)

这篇文章开始介绍ArrayList。ArrayList基本上是我们在平时的开发当中,使用最多的一个集合类了,它是一个其容量能够动态增长的动态数组。所以这篇文章,旨在从源码的角度进行分析和理解。为了使得文章更加有条理,还是先给出这篇文章的大致脉络:

首先,ArrayList的基本介绍和源码API(只给出方法分析,重要的方法给出详细代码)。然后,介绍遍历ArrayList的几种方式接下来,叙述一下ArrayList与其他集合关键字的区别和优缺点最后,进行一个总结

OK,开始今天的文章。

一、ArrayList认识

1、概念

概念:ArrayList是一个其容量能够动态增长的动态数组。但是他又和数组不一样,下面会分析对比。它继承了AbstractList,实现了List、RandomAccess, Cloneable, java.io.Serializable。

2、继承关系

为此我们需要先知道ArrayList在整个java集合框架体系里面处于一个什么样的位置。一张图来说明:

9858c8956c863791b8850ede4061ef25.png

从上面我们发现ArrayList的最根部就是实现了Collection接口。下面我们深入进去,看看从ArrayList的角度来分析一下继承关系:

2ab309e3f1a0ff0aa2fa023cdb8b82fa.png

上面这张图基本上描述的很清晰了,实现了四个接口一个抽象类。它继承了AbstractList抽象类,实现了List、RandomAccess, Cloneable, Serializable接口。

它继承于AbstractList,实现了List,RandomAccess[随机访问],Cloneable[可克隆], java.io.Serializable[序列化]这些接口。ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输和Vector不同,ArrayList中的操作不是线程安全的。所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。3、特点

基本的ArrayList,常常用于随机访问元素,但是在List中间插入和移除元素时较慢。同时,ArrayList的操作不是线程安全的!一般在单线程中才使用ArrayList,而在多线程中一般使用Vector或者CopyOnWriteArrayList。对于这些我们先有一个概念。

OK,对于ArrayList的基本认识,主要就是知道是动态的数组,还有其继承关系就可以了,关于他的特点,我们知道其是数组,那么特点就和数组的一样了:随机访问元素比较好。

二、从源码分析ArrayList

既然它继承了AbstractList抽象类,实现了List、RandomAccess, Cloneable, Serializable接口。 那么他肯定就会有继承过来的特性,下面对其方法先进行一个归纳整理。

1、构造方法

ArrayList():构造一个初始容量为10的空列表ArrayList(Collection<?extend E> c):构造一个包含指定元素的列表ArrayList( int initialCapcity ):构造一个具有初始容量值得空列表下面看一下代码实现:

02546b641892191516366246334df961.png

2、增删改查操作

对于增删改查的基本操作,在这里只给出一些比较重要的源代码,实现起来比较简单的就不给出了。

(1)增加元素

add(E e):添加一个元素到列表的末尾。add( int index, E element ) :在指定的位置添加元素addAll( Collection extends E> c ):添加一个集合到元素的末尾.以上返回类型是booleanensureCapcity(int minCapcity):确保列表中含有minCapcity的最小容量下面代码看一下其实现(给出第一个增加元素的方法实现):

733d2177b4ce5b62d994f061e948be87.png

下面代码看一下其实现(给出第二个增加元素的方法实现):

9a635e4f8a74d5e337dbd032f7eb3905.png

(2)删除操作

remove(Object o):删除列表中第一个出现O的元素remove( int index):删除列表中指定位置的元素removeAll(Collection> c):删除列表中包含C的所有元素removeIf(Predictcate super E> filter):删除列表中给定谓词的所有元素removeRange( int from,int to ):删除从from到to的所有元素clear():清除所有的元素。返回类型为void看代码实现:

fb5340f78817401af38b638b8c12ab45.png

上面的只是其中一种实现方式,再来看一种:

f0671433a1c3a39bbc1ac6a21bb7c83b.png

(3)更改操作

retainAll( Collection> c ):仅仅保留列表中和C相同的元素,相当于&运算set(int index,E element):用element替换index位置上的元素。size():返回此列表的元素数sort(Comparator super E> c):按照指定的排序规则排序subList( int from , int to ):返回从from到to之间的列表toArray():将列表转化为数组trimToSize( ):修改当前实例的容量是列表的当前大小。我们看一下set操作:

36bcd2de8b473aabe3f367df9f49fcb4.png

再来看看subList操作:

7a92adf976a86ff42e049b69337147e2.png

还有trimToSize

14ce2d62a34744f0baadb7a409123304.png

最后就是toArray用法

62716ff5319d0a6731236da8075309e2.png

(4)查操作

contains(Object o):如果包含元素o,则返回为trueget(int index):返回指定索引的元素indexOf( Object o ):返回此列表中指定元素的第一次出现的索引,如果列表不包含此元素,返回-1lastindexOf( Object o ):返回此列表中指定元素的最后一次出现的索引,如果列表不包含此元素,返回-1isEmpty():如果列表为空,返回true.iterator():返回列表中元素的迭代器listIterator():返回列表的列表迭代器(按适当的顺序)listIterator(int index):从适当的位置返回列表的列表迭代器(按照正确的顺序)先看一下contain()

217c56926b40af40a6a3d5fb6719b90d.png

还有重要的iterator方法,不过在这里我们不去看,因为在遍历的时候会使用。

三、遍历

在这里给出三种常用的遍历方法

07a3b527e0375d5db5e6772da2b6b885.png

要问哪一种效率最高:第二种遍历的效率是最高的。想要验证的话,你只需要加一个时间差就好了。

四、ArrayList需要知道的几个问题

1、与数组的比较

e5d4e6a693542d9ff2458c671e35d04f.png

2、与LinkList、Vector对比区别

分析得出下面结论:

(1)ArrayList 本质上是一个可改变大小的数组.当元素加入时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问.元素顺序存储 ,随机访问很快,删除非头尾元素慢,新增元素慢而且费资源 ,较适用于无频繁增删的情况 ,比数组效率低,如果不是需要可变数组,可考虑使用数组 ,非线程安全.

(2)LinkedList 是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList. 适用于 :没有大规模的随机读取,有大量的增加/删除操作.随机访问很慢,增删操作很快,不耗费多余资源 ,允许null元素,非线程安全.

(3)Vector (类似于ArrayList)但其是同步的,开销就比ArrayList要大。如果你的程序本身是线程安全的,那么使用ArrayList是更好的选择。 Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%.

五、总结

ArrayList总体来说比较简单,不过ArrayList还有以下一些特点:

ArrayList自己实现了序列化和反序列化的方法,因为它自己实现了private void writeObject(java.io.ObjectOutputStream s)、private void readObject(java.io.ObjectInputStream s) 方法ArrayList基于数组方式实现,无容量的限制(会扩容)添加元素时可能要扩容(所以最好预判一下),删除元素时不会减少容量(若希望减少容量,trimToSize()),删除元素时,将删除掉的位置元素置为null,下次gc就会回收这些元素所占的内存空间。线程不安全,会出现fall-fail。下一篇文章会详细讲,add(int index, E element):添加元素到数组中指定位置的时候,需要将该位置及其后边所有的元素都整块向后复制一位get(int index):获取指定位置上的元素时,可以通过索引直接获取(O(1))remove(Object o)需要遍历数组remove(int index)不需要遍历数组,只需判断index是否符合条件即可,效率比remove(Object o)高contains(E)需要遍历数组使用iterator遍历可能会引发多线程异常谢谢大家,如有问题还请批评指正

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值