ImageVerifierCode 换一换
格式:DOCX , 页数:11 ,大小:21.47KB ,
资源ID:3804602      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/3804602.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Java集合ArrayList的实现原理.docx)为本站会员(b****4)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Java集合ArrayList的实现原理.docx

1、Java集合ArrayList的实现原理Java集合-ArrayList的实现原理ArrayList概述ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。 ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了Ra

2、ndomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。 ArrayList的实现对于ArrayList而言,它实现List接口、

3、底层使用数组保存所有元素。其操作基本上是对数组的操作。下面我们来分析ArrayList的源代码:私有属性 /* * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData = EMPTY_ELEMENTDATA will be expanded to * DEFAULT_CAPACITY when t

4、he first element is added. */ private transient Object elementData; /* * The size of the ArrayList (the number of elements it contains). * * serial */ private int size;elementData存储ArrayList内的元素,size表示它包含的元素的数量。有个关键字需要解释:transient。 Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serial

5、ization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。构造方法ArrayList提供了三种方式的构造器,可以构造一个默认初始容量为10的空列表、构造一个指定初始容量的空列表以及构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。 /* * Constructs an empty list with the specified initial capacity. * * param initialCapacity the initial capacity o

6、f the list * throws IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) super(); if (initialCapacity 0) throw new IllegalArgumentException(Illegal Capacity: + initialCapacity); this.elementData = new ObjectinitialCapacity; /* * Constructs

7、 an empty list with an initial capacity of ten. */ public ArrayList() super(); this.elementData = EMPTY_ELEMENTDATA; /* * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collections * iterator. * * param c the collection whose elements a

8、re to be placed into this list * throws NullPointerException if the specified collection is null */ public ArrayList(Collection c) elementData = c.toArray(); size = elementData.length; / c.toArray might (incorrectly) not return Object (see 6260652) if (elementData.getClass() != Object.class) element

9、Data = Arrays.copyOf(elementData, size, Object.class); 元素存储ArrayList提供了set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection/ 用指定的元素替代此列表中指定位置上的元素,并返回以前位于该位置上的元素。 public E set(int index, E element) RangeCheck(index); /范围检查 E oldValue = (E) elementDataindex; elementDataindex

10、= element; return oldValue; / 将指定的元素添加到此列表的尾部。 public boolean add(E e) ensureCapacity(size + 1); elementDatasize+ = e; return true; / 将指定的元素插入此列表中的指定位置。 / 如果当前位置有元素,则向右移动当前位于该位置的元素以及所有后续元素(将其索引加1)。 public void add(int index, E element) if (index size | index 0) throw new IndexOutOfBoundsException(In

11、dex: +index+, Size: +size); / 如果数组长度不足,将进行扩容。 ensureCapacity(size+1); / Increments modCount! / 将 elementData中从Index位置开始、长度为size-index的元素, / 拷贝到从下标为index+1位置开始的新的elementData数组中。 / 即将当前位于该位置的元素以及所有后续元素右移一个位置。 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementDataindex

12、= element; size+; / 按照指定collection的迭代器所返回的元素顺序,将该collection中的所有元素添加到此列表的尾部。 public boolean addAll(Collection c) Object a = c.toArray(); int numNew = a.length; ensureCapacity(size + numNew); / Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; /

13、 从指定的位置开始,将指定collection中的所有元素插入到此列表中。 public boolean addAll(int index, Collection c) if (index size | index 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; 元素读取/ 返回此列表中指定位置上的元素。 pu

14、blic E get(int index) RangeCheck(index); return (E) elementDataindex; 元素删除romove(int index): / 移除此列表中指定位置上的元素。 public E remove(int index) RangeCheck(index); modCount+; E oldValue = (E) elementDataindex; int numMoved = size - index - 1; if (numMoved 0) System.arraycopy(elementData, index+1, elementDa

15、ta, index, numMoved); elementData-size = null; / Let gc do its work return oldValue; 首先是检查范围,修改modCount,保留将要被移除的元素,将移除位置之后的元素向前挪动一个位置,将list末尾元素置空(null),返回被移除的元素。 remove(Object o)/ 移除此列表中首次出现的指定元素(如果存在)。这是应为ArrayList中允许存放重复的元素。 public boolean remove(Object o) / 由于ArrayList中允许存放null,因此下面通过两种情况来分别处理。 i

16、f (o = null) for (int index = 0; index size; index+) if (elementDataindex = null) / 类似remove(int index),移除列表中指定位置上的元素。 fastRemove(index); return true; else for (int index = 0; index 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData-size = null; / Let gc do its work

17、 removeRange(int fromIndex,int toIndex)protected void removeRange(int fromIndex, int toIndex) modCount+; int numMoved = size - toIndex; System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); / Let gc do its work int newSize = size - (toIndex-fromIndex); while (size != newSize) ele

18、mentData-size = null; 执行过程是将elementData从toIndex位置开始的元素向前移动到fromIndex,然后将toIndex位置之后的元素全部置空顺便修改size。 这个方法是protected,及受保护的方法,为什么这个方法被定义为protected呢?这是一个解释,但是可能不容易看明白。先看下面这个例子: ArrayList ints = new ArrayList(Arrays.asList(0, 1, 2, 3, 4, 5, 6); / fromIndex low endpoint (inclusive) of the subList / toInde

19、x high endpoint (exclusive) of the subList ints.subList(2, 4).clear(); System.out.println(ints); 输出结果是0, 1, 4, 5, 6调整数组容量ensureCapacity从上面介绍的向ArrayList中存储元素的代码中,我们看到,每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,以满足添加数据的需求。数组扩容通过一个公开的方法ensureCapacity(int minCapacity)来实现。在实际添加大量元素前,我也可以使用ensure

20、Capacity来手动增加ArrayList实例的容量,以减少递增式再分配的数量。 public void ensureCapacity(int minCapacity) modCount+; int oldCapacity = elementData.length; if (minCapacity oldCacity) Object oldData = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; /增加50%+1 if (newCapacity minCapacity) newCapacity = minCapacity;

21、/ minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); 从上述代码中可以看出,数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加A

22、rrayList实例的容量。Object oldData = elementData;/为什么要用到oldData 乍一看来后面并没有用到关于oldData, 这句话显得多此一举!但是这是一个牵涉到内存管理的类, 所以要了解内部的问题。 而且为什么这一句还在if的内部,这跟elementData = Arrays.copyOf(elementData, newCapacity); 这句是有关系的,下面这句Arrays.copyOf的实现时新创建了newCapacity大小的内存,然后把老的elementData放入。好像也没有用到oldData,有什么问题呢。问题就在于旧的内存的引用是elem

23、entData, elementData指向了新的内存块,如果有一个局部变量oldData变量引用旧的内存块的话,在copy的过程中就会比较安全,因为这样证明这块老的内存依然有引用,分配内存的时候就不会被侵占掉,然后copy完成后这个局部变量的生命期也过去了,然后释放才是安全的。不然在copy的的时候万一新的内存或其他线程的分配内存侵占了这块老的内存,而copy还没有结束,这将是个严重的事情。 关于ArrayList和Vector区别如下:ArrayList在内存不够时默认是扩展50% + 1个,Vector是默认扩展1倍。Vector提供indexOf(obj, start)接口,Array

24、List没有。Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。ArrayList还给我们提供了将底层数组的容量调整为当前列表保存的实际元素的大小的功能。它可以通过trimToSize方法来实现。代码如下:public void trimToSize() modCount+; int oldCapacity = elementData.length; if (size oldCapacity) elementData = Arrays.copyOf(elementData, size); 由于elementData的长度会被拓展,size标记的

25、是其中包含的元素的个数。所以会出现size很小但elementData.length很大的情况,将出现空间的浪费。trimToSize将返回一个新的数组给elementData,元素内容保持不变,length和size相同,节省空间。转为静态数组toArray注意ArrayList的两个转化为静态数组的toArray方法。第一个, 调用Arrays.copyOf将返回一个数组,数组内容是size个elementData的元素,即拷贝elementData从0至size-1位置的元素到新数组并返回。public Object toArray() return Arrays.copyOf(elem

26、entData, size); 第二个,如果传入数组的长度小于size,返回一个新的数组,大小为size,类型与传入数组相同。所传入数组长度与size相等,则将elementData复制到传入数组中并返回传入的数组。若传入数组长度大于size,除了复制elementData外,还将把返回数组的第size个元素置为空。 public T toArray(T a) if (a.length size) asize = null; return a; 总结:关于ArrayList的源码,给出几点比较重要的总结: 1、注意其三个不同的构造方法。无参构造方法构造的ArrayList的容量默认为10,带有Collection参数的构造方法,将Collection转化为数组赋给ArrayList的实现数组elementData。2、注意扩充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1个,也可能是一组)时,都要调用该方法来确保足够的容量。当容量不足以容纳当前的元素个数时,就设置新的容量为旧的容量的1.5倍加1,如果设置后的新容量还不够,则直接新容量设置为传入的参数(也就是所需的容量),而后用Arrays.copyof()方法将元素拷贝到新的数组(详见下面的第3点)。从中可以看出,当容量不够时,每次增加元素,都要将原来的元素拷贝到一

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1