首页 / JAVA / JAVA源码学习-ArrayList
JAVA源码学习-ArrayList
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了JAVA源码学习-ArrayList,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含23627字,纯文字阅读大概需要34分钟。
内容图文
![JAVA源码学习-ArrayList](/upload/InfoBanner/zyjiaocheng/716/0bd5a291e010443c9e12db2a50b18b06.jpg)
ArrayList其实是支持增加,删除,修改,查询元素的数组,提供一些为我们熟知的方法去使用,例如add,remove,get等,她是动态的,可以自由扩展容量,是一种比较常用的数据结构,为什么常用,因为她方便。
简单概括了ArrayList特点之后,正式开启源码解读之旅
(最前面有一大坨英文,有时间再慢慢翻译,如果觉得有必要的话~)
首先看ArrayList的继承关系和声明
她继承于AbstractList,实现了List, RandomAccess, Cloneable,java.io.Serializable这些接口。
ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
ArrayList 实现了RandomAccess接口,即提供了随机访问功能。RandomAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。稍后,我们会比较List的“快速随机访问”和“通过Iterator迭代器访问”的效率。
ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。
ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输,但其中一个属性是不允许被序列化的哦,接下来可以看到具体是哪个属性。
和Vector不同,ArrayList中的操作不是线程安全的。所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。
ArrayList的属性
private?static?final?long?serialVersionUID?=?8683452581122892189L;
????/**
?????*?The?array?buffer?into?which?the?elements?of?the?ArrayList?are?stored.
?????*?The?capacity?of?the?ArrayList?is?the?length?of?this?array?buffer.
?????*/
????private?transient?Object[]?elementData;
????/**
?????*?The?size?of?the?ArrayList?(the?number?of?elements?it?contains).
?????*
?????*?@serial
?????*/
????private?int?size;
/**
?????*?The?maximum?size?of?array?to?allocate.
?????*?Some?VMs?reserve?some?header?words?in?an?array.
?????*?Attempts?to?allocate?larger?arrays?may?result?in
?????*?OutOfMemoryError:?Requested?array?size?exceeds?VM?limit
?????*/
????private?static?final?int?MAX_ARRAY_SIZE?=?Integer.MAX_VALUE?-?8;
第一个长整形serialVersionUID是为序列化使用的,所以其实只定义了三个属性,对象数组elementData(存储了ArrayList的元素,ArrayList的容量其实就是这个数组的长度),整型size(存储ArrayList中元素的实际容量), 私有静态final类型MAX_ARRAY_SIZE,是为ArrayList定义动态扩充容量的上限。这里也许有人会有疑问,为什么不直接定义成整型的最大值,而是要定义成整型最大值-8呢?原因是某些特定环境下数组里会默认保留一些头信息,ArrayList在设定最大容量时需要将这些信息的长度排除掉,否则可能会出现明明没到整型最大值,但仍抛出OutOfMemoryError异常。
需要注意的是,这里的elementData是用关键字transient修饰的,使用transient修饰是用来表示一个域不是该对象串行化的一部分,即当ArrayList被串行化的时候,elementData的值不包括在串行化表示中,而非transient的变量size则是被包括进去的。那么问题来了,为什么ArrayList中的元素不能被串行化呢?Mark一下留待以后解决~
ArrayList的构造函数
/**
?????*?Constructs?an?empty?list?with?the?specified?initial?capacity.
?????*
?????*?@param??initialCapacity??the?initial?capacity?of?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?Object[initialCapacity];
????}
????/**
?????*?Constructs?an?empty?list?with?an?initial?capacity?of?ten.
?????*/
????public?ArrayList()?{
????????this(10);
????}
????/**
?????*?Constructs?a?list?containing?the?elements?of?the?specified
?????*?collection,?in?the?order?they?are?returned?by?the?collection's
?????*?iterator.
?????*
?????*?@param?c?the?collection?whose?elements?are?to?be?placed?into?this?list
?????*?@throws?NullPointerException?if?the?specified?collection?is?null
?????*/
????public?ArrayList(Collection<??extends?E>?c)?{
????????elementData?=?c.toArray();
????????size?=?elementData.length;
????????//?c.toArray?might?(incorrectly)?not?return?Object[]?(see?6260652)
????????if?(elementData.getClass()?!=?Object[].class)
????????????elementData?=?Arrays.copyOf(elementData,?size,?Object[].class);
????}
有三个:
ArrayList(int initalCapacity) :带参数的构造函数
使用initalCapacity来初始化elementData数组的大小,若小于零,抛出IllegalArgumentException异常;
ArrayList():默认的构造函数
使用带参数的构造函数初始化一个大小为10的ArrayList;
ArrayList(Collection<E> c)
先将提供的几何转变为数组,c.toArray()方法有可能返回的不是对象数组,这种情况下使用Arrays.copyOf转为对象数组。
ArrayList的其他方法
1. trimToSize()
/**
?????*?Trims?the?capacity?of?this?<tt>ArrayList</tt>?instance?to?be?the
?????*?list's?current?size.??An?application?can?use?this?operation?to?minimize
?????*?the?storage?of?an?<tt>ArrayList</tt>?instance.
?????*/
????public?void?trimToSize()?{
????????modCount++;
????????int?oldCapacity?=?elementData.length;
????????if?(size?<?oldCapacity)?{
????????????elementData?=?Arrays.copyOf(elementData,?size);
????????}
????}
有些时候对象数组的长度跟ArrayList定义的size属性不一定是相等的,那么可以显式地调用此方法确保二者的统一,从而避免不必要的空间浪费。
2.add(E): 在数组的末尾插入元素
add(int, E):在指定位置插入元素
这些大家应该都知道,因为这两个方法比较常用。但是他们是如何实现的呢?
/**
?????*?Appends?the?specified?element?to?the?end?of?this?list.
?????*
?????*?@param?e?element?to?be?appended?to?this?list
?????*?@return?<tt>true</tt>?(as?specified?by?{@link?Collection#add})
?????*/
????public?boolean?add(E?e)?{
????????ensureCapacityInternal(size?+?1);??//?Increments?modCount!!
????????elementData[size++]?=?e;
????????return?true;
????}
????/**
?????*?Inserts?the?specified?element?at?the?specified?position?in?this
?????*?list.?Shifts?the?element?currently?at?that?position?(if?any)?and
?????*?any?subsequent?elements?to?the?right?(adds?one?to?their?indices).
?????*
?????*?@param?index?index?at?which?the?specified?element?is?to?be?inserted
?????*?@param?element?element?to?be?inserted
?????*?@throws?IndexOutOfBoundsException?{@inheritDoc}
?????*/
????public?void?add(int?index,?E?element)?{
????????rangeCheckForAdd(index);
????????ensureCapacityInternal(size?+?1);??//?Increments?modCount!!
????????System.arraycopy(elementData,?index,?elementData,?index?+?1,
?????????????????????????size?-?index);
????????elementData[index]?=?element;
????????size++;
????}
add(E), 将新的元素e插入到size的位置,然后将size+1备用,返回添加成功。
add(int,E) 先检查你要插入的位置index,如果小于0或是比ArrayList的size还大,则抛出IndexOutOfBoundsException异常,这个异常我相信大家都有见过。然后调用System.arraycopy将原数组elementData的index位置到size-index位置之间的元素移动到index+1开始以后的位置去,这么说有点绕口,说白了就是将elementData数组里index以后的元素向后平移一个位置,空出index这个位置给要增加的元素element,然后将size属性加1。
比较两个方法我们可以发现二者都使用到了ensureCapacityInternal(size + 1)方法,那么这个方法不说大家也可以猜出来,是扩充容量用的。怎么实现的,看源码:
/**
?????*?Increases?the?capacity?of?this?<tt>ArrayList</tt>?instance,?if
?????*?necessary,?to?ensure?that?it?can?hold?at?least?the?number?of?elements
?????*?specified?by?the?minimum?capacity?argument.
?????*
?????*?@param???minCapacity???the?desired?minimum?capacity
?????*/
????public?void?ensureCapacity(int?minCapacity)?{
????????if?(minCapacity?>?0)
????????????ensureCapacityInternal(minCapacity);
????}
????private?void?ensureCapacityInternal(int?minCapacity)?{
????????modCount++;
????????//?overflow-conscious?code
????????if?(minCapacity?-?elementData.length?>?0)
????????????grow(minCapacity);
????}
????/**
?????*?Increases?the?capacity?to?ensure?that?it?can?hold?at?least?the
?????*?number?of?elements?specified?by?the?minimum?capacity?argument.
?????*
?????*?@param?minCapacity?the?desired?minimum?capacity
?????*/
????private?void?grow(int?minCapacity)?{
????????//?overflow-conscious?code
????????int?oldCapacity?=?elementData.length;
????????int?newCapacity?=?oldCapacity?+?(oldCapacity?>>?1);
????????if?(newCapacity?-?minCapacity?<?0)
????????????newCapacity?=?minCapacity;
????????if?(newCapacity?-?MAX_ARRAY_SIZE?>?0)
????????????newCapacity?=?hugeCapacity(minCapacity);
????????//?minCapacity?is?usually?close?to?size,?so?this?is?a?win:
????????elementData?=?Arrays.copyOf(elementData,?newCapacity);
????}
????private?static?int?hugeCapacity(int?minCapacity)?{
????????if?(minCapacity?<?0)?//?overflow
????????????throw?new?OutOfMemoryError();
????????return?(minCapacity?>?MAX_ARRAY_SIZE)??
????????????Integer.MAX_VALUE?:
????????????MAX_ARRAY_SIZE;
????}
第一个方法是ArrayList暴露出来让你自己扩充容量用的,目前我没使用过,都是让ArrayList内部帮我扩充容量。
真正起作用的是剩下的三个私有方法,综合起来看:我在size的基础上增加一位(因为要add一个元素么),但是发现这时候size+1的值比当前对象数组的长度还要大,此时就要去扩充数组容量了,进入了grow方法,她会根据规则对数组对象进行扩充。先说明一下两个值:
A:minCapacity,就是当前size+1后的值,要求扩充到多大;B:newCapacity,当前数组对象长度*3/2(JKD1.7以前的版本是用算数表达式实现的,1.7的版本变成了位右移表达式,结果是一样的,熟悉位移的童鞋应该知道,这么改是有助于提高执行效率和内存使用的)
扩充的规则是:
如果B<A:不够我要求扩充的容量,那么就按照A来扩充。一般不会有,但特殊情况比如当前size的值比实际数组长度大(没有用trimToSize()释放)。
如果A<B<MAX_ARRAY_SIZE: 这个是正常情况下默认扩充的容量大小,即原数组对象的3/2,即扩充了原长度的一半。
如果B>MAX_ARRAY_SIZE:扩充不了原长度的一半了,则使用上限值去扩充。
为什么说ArrayList是一个动态数组,答案就在这几个方法里面。
那么同理add(Collection)和add(int,Collection)实现原理是一样的,无非多了一个将Collection转换成数组的操作,这里不再赘述。
3 size()
/**
?????*?Returns?the?number?of?elements?in?this?list.
?????*
?????*?@return?the?number?of?elements?in?this?list
?????*/
????public?int?size()?{
????????return?size;
????}
这里使用这个public方法封装size私有属性,返回的是当前ArrayList的大小,这点也跟数组的length属性区别开了。
4 isEmpty()
/**
?????*?Returns?<tt>true</tt>?if?this?list?contains?no?elements.
?????*
?????*?@return?<tt>true</tt>?if?this?list?contains?no?elements
?????*/
????public?boolean?isEmpty()?{
????????return?size?==?0;
????}
返回ArrayList是否为空。
5 contains(Object)
/**
?????*?Returns?<tt>true</tt>?if?this?list?contains?the?specified?element.
?????*?More?formally,?returns?<tt>true</tt>?if?and?only?if?this?list?contains
?????*?at?least?one?element?<tt>e</tt>?such?that
?????*?<tt>(o==null???e==null?:?o.equals(e))</tt>.
?????*
?????*?@param?o?element?whose?presence?in?this?list?is?to?be?tested
?????*?@return?<tt>true</tt>?if?this?list?contains?the?specified?element
?????*/
????public?boolean?contains(Object?o)?{
????????return?indexOf(o)?>=?0;
????}
使用indexOf方法来判断当前数组是否包含元素o,接着来看indexOf方法。
6 indexOf(Object)
lastIndexOf(Object)
/**
?????*?Returns?the?index?of?the?first?occurrence?of?the?specified?element
?????*?in?this?list,?or?-1?if?this?list?does?not?contain?the?element.
?????*?More?formally,?returns?the?lowest?index?<tt>i</tt>?such?that
?????*?<tt>(o==null???get(i)==null?:?o.equals(get(i)))</tt>,
?????*?or?-1?if?there?is?no?such?index.
?????*/
????public?int?indexOf(Object?o)?{
????????if?(o?==?null)?{
????????????for?(int?i?=?0;?i?<?size;?i++)
????????????????if?(elementData[i]==null)
????????????????????return?i;
????????}?else?{
????????????for?(int?i?=?0;?i?<?size;?i++)
????????????????if?(o.equals(elementData[i]))
????????????????????return?i;
????????}
????????return?-1;
????}
????/**
?????*?Returns?the?index?of?the?last?occurrence?of?the?specified?element
?????*?in?this?list,?or?-1?if?this?list?does?not?contain?the?element.
?????*?More?formally,?returns?the?highest?index?<tt>i</tt>?such?that
?????*?<tt>(o==null???get(i)==null?:?o.equals(get(i)))</tt>,
?????*?or?-1?if?there?is?no?such?index.
?????*/
????public?int?lastIndexOf(Object?o)?{
????????if?(o?==?null)?{
????????????for?(int?i?=?size-1;?i?>=?0;?i--)
????????????????if?(elementData[i]==null)
????????????????????return?i;
????????}?else?{
????????????for?(int?i?=?size-1;?i?>=?0;?i--)
????????????????if?(o.equals(elementData[i]))
????????????????????return?i;
????????}
????????return?-1;
????}
使用了for循环对数组进行遍历,indexOf和lastIndexOf无非是前者从前往后遍历,后者从后往前遍历,如果当前元素与o相等,则返回当前元素索引。需要注意的是,ArrayList是支持对null的查找的。
这里多说一下ArrayList的遍历方式,有三种
第一种:利用迭代器遍历。即通过Iterator去遍历
Integer?value?=?null;
Iterator?iter?=?list.iterator();
while?(iter.hasNext())?{
????value?=?(Integer)iter.next();
}
第二种,随机访问,通过索引值遍历(由于实现了RandomAccess接口,支持通过索引访问元素)
Integer?value?=?null;
int?size?=?list.size();
for?(int?i=0;?i<size;?i++)?{
????value?=?(Integer)list.get(i);??????
}
第三种,for循环遍历。
Integer?value?=?null;
for?(Integer?integ:list)?{
????value?=?integ;
}
这三种遍历方式,使用随机访问(即通过索引序号访问)效率最高,而使用迭代器效率最低。至于为什么,有兴趣的童鞋可以下去研究一下。
7 clone()
/**
?????*?Returns?a?shallow?copy?of?this?<tt>ArrayList</tt>?instance.??(The
?????*?elements?themselves?are?not?copied.)
?????*
?????*?@return?a?clone?of?this?<tt>ArrayList</tt>?instance
?????*/
????public?Object?clone()?{
????????try?{
????????????@SuppressWarnings("unchecked")
????????????????ArrayList<E>?v?=?(ArrayList<E>)?super.clone();
????????????v.elementData?=?Arrays.copyOf(elementData,?size);
????????????v.modCount?=?0;
????????????return?v;
????????}?catch?(CloneNotSupportedException?e)?{
????????????//?this?shouldn't?happen,?since?we?are?Cloneable
????????????throw?new?InternalError();
????????}
????}
调用父类的clone方法返回一个对象的副本,将返回对象的elementData数组的内容赋值为原对象elementData数组的内容
8 toArray()
toArray(T[])
public?Object[]?toArray()?{
????????return?Arrays.copyOf(elementData,?size);
????}
@SuppressWarnings("unchecked")
????public?<T>?T[]?toArray(T[]?a)?{
????????if?(a.length?<?size)
????????????//?Make?a?new?array?of?a's?runtime?type,?but?my?contents:
????????????return?(T[])?Arrays.copyOf(elementData,?size,?a.getClass());
????????System.arraycopy(elementData,?0,?a,?0,?size);
????????if?(a.length?>?size)
????????????a[size]?=?null;
????????return?a;
????}
toArray() 调用Arrays.copyOf方法返回一个数组,内容是size个elementData元素,即把elementData中从0到size-1的元素拷贝到新的数组并返回。
toArray(T[]) 如果传入数组的长度小于size,则返回一个新的数组,大小为size,类型与传入数组相同;如果传入数组的长度大于或等于size,则将elementData全部拷贝到a中并返回,其中如果传入数组长度大于size,除了复制外,还将返回数组a中的size位置置为null。
9 elementData(int)
@SuppressWarnings("unchecked")
????E?elementData(int?index)?{
????????return?(E)?elementData[index];
????}
返回索引为index的数组元素
10 get(int)
/**
?????*?Returns?the?element?at?the?specified?position?in?this?list.
?????*
?????*?@param??index?index?of?the?element?to?return
?????*?@return?the?element?at?the?specified?position?in?this?list
?????*?@throws?IndexOutOfBoundsException?{@inheritDoc}
?????*/
????public?E?get(int?index)?{
????????rangeCheck(index);
????????return?elementData(index);
????}
先校验index是否越界,不越界就返回当前索引为index的数组元素。
11 set(int, E)
/**
?????*?Replaces?the?element?at?the?specified?position?in?this?list?with
?????*?the?specified?element.
?????*
?????*?@param?index?index?of?the?element?to?replace
?????*?@param?element?element?to?be?stored?at?the?specified?position
?????*?@return?the?element?previously?at?the?specified?position
?????*?@throws?IndexOutOfBoundsException?{@inheritDoc}
?????*/
????public?E?set(int?index,?E?element)?{
????????rangeCheck(index);
????????E?oldValue?=?elementData(index);
????????elementData[index]?=?element;
????????return?oldValue;
????}
先校验index是否越界,不越界就将索引为index的数组元素另存为一个副本oldValue,然后将入参element插入到该索引位置,返回副本值oldValue。原本以为调用set方法无返回值的童鞋是不是很诧异?
12 clear()
/**
?????*?Removes?all?of?the?elements?from?this?list.??The?list?will
?????*?be?empty?after?this?call?returns.
?????*/
????public?void?clear()?{
????????modCount++;
????????//?Let?gc?do?its?work
????????for?(int?i?=?0;?i?<?size;?i++)
????????????elementData[i]?=?null;
????????size?=?0;
????}
用一个for循环遍历,将所有的元素设置为null,然后将size清零。这里需要注意的是数组elementData的实际长度并没有改变,此时虽然arraylist的大小为0,但仍然占用elementData.length的空间,这就是前面提到的trimToSize方法来释放多余占用的空间。
13 remove(int)
/**
?????*?Removes?the?element?at?the?specified?position?in?this?list.
?????*?Shifts?any?subsequent?elements?to?the?left?(subtracts?one?from?their
?????*?indices).
?????*
?????*?@param?index?the?index?of?the?element?to?be?removed
?????*?@return?the?element?that?was?removed?from?the?list
?????*?@throws?IndexOutOfBoundsException?{@inheritDoc}
?????*/
????public?E?remove(int?index)?{
????????rangeCheck(index);
????????modCount++;
????????E?oldValue?=?elementData(index);
????????int?numMoved?=?size?-?index?-?1;
????????if?(numMoved?>?0)
????????????System.arraycopy(elementData,?index+1,?elementData,?index,
?????????????????????????????numMoved);
????????elementData[--size]?=?null;?//?Let?gc?do?its?work
????????return?oldValue;
????}
先index索引越界校验,保存原来index位置数组元素的副本oldValue,然后如果index跟elementData最后一位索引值相等,即移除最后一个元素,更新size,否则在移除元素前将数组index之后的所有元素向前移动一位。移除成功后返回移除的元素值
14 remove(Object)
/**
?????*?Removes?the?first?occurrence?of?the?specified?element?from?this?list,
?????*?if?it?is?present.??If?the?list?does?not?contain?the?element,?it?is
?????*?unchanged.??More?formally,?removes?the?element?with?the?lowest?index
?????*?<tt>i</tt>?such?that
?????*?<tt>(o==null???get(i)==null?:?o.equals(get(i)))</tt>
?????*?(if?such?an?element?exists).??Returns?<tt>true</tt>?if?this?list
?????*?contained?the?specified?element?(or?equivalently,?if?this?list
?????*?changed?as?a?result?of?the?call).
?????*
?????*?@param?o?element?to?be?removed?from?this?list,?if?present
?????*?@return?<tt>true</tt>?if?this?list?contained?the?specified?element
?????*/
????public?boolean?remove(Object?o)?{
????????if?(o?==?null)?{
????????????for?(int?index?=?0;?index?<?size;?index++)
????????????????if?(elementData[index]?==?null)?{
????????????????????fastRemove(index);
????????????????????return?true;
????????????????}
????????}?else?{
????????????for?(int?index?=?0;?index?<?size;?index++)
????????????????if?(o.equals(elementData[index]))?{
????????????????????fastRemove(index);
????????????????????return?true;
????????????????}
????????}
????????return?false;
????}
????/*
?????*?Private?remove?method?that?skips?bounds?checking?and?does?not
?????*?return?the?value?removed.
?????*/
????private?void?fastRemove(int?index)?{
????????modCount++;
????????int?numMoved?=?size?-?index?-?1;
????????if?(numMoved?>?0)
????????????System.arraycopy(elementData,?index+1,?elementData,?index,
?????????????????????????????numMoved);
????????elementData[--size]?=?null;?//?Let?gc?do?its?work
????}
这个方法的作用是remove一个元素对象。那么就需要找到这个元素在数组中位置index,然后remove(index)就行了,查找index的方法大家是不是看着眼熟,其实就是前面讲到的indexOf(Object)方法,只不过找到以后多了一个移除的动作。那么问题来了,移除用了一个新的方法fastRemove,而没用之前写好的remove方法,这是因为此时已经确定找到了index,就不需要像remove方法里先校验一次是否越界了。
15 removeRange(int,int)
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)
????????????elementData[--size]?=?null;
????}
方法的执行过程是 将elementData从toIndex位置开始的元素向前移动到fromIndex,然后将toIndex位置之后的元素全部置空顺便修改size。
但是为什么设置为protected受保护的方法呢?下面这个链接做了解释,但看不怎么明白,因为JDK1.7已经在ArrayList方法里实现了SubList,那么绕一大圈貌似没什么卵用。大家可以交流下自己的理解。
http://www.cnblogs.com/hzmark/archive/2012/12/19/ArrayList_removeRange.html
16 removeAll(Collection)
retainAll(Collection)
public?boolean?removeAll(Collection<?>?c)?{
????????return?batchRemove(c,?false);
????}
public?boolean?retainAll(Collection<?>?c)?{
????????return?batchRemove(c,?true);
????}
????private?boolean?batchRemove(Collection<?>?c,?boolean?complement)?{
????????final?Object[]?elementData?=?this.elementData;
????????int?r?=?0,?w?=?0;
????????boolean?modified?=?false;
????????try?{
????????????for?(;?r?<?size;?r++)
????????????????if?(c.contains(elementData[r])?==?complement)
????????????????????elementData[w++]?=?elementData[r];
????????}?finally?{
????????????//?Preserve?behavioral?compatibility?with?AbstractCollection,
????????????//?even?if?c.contains()?throws.
????????????if?(r?!=?size)?{
????????????????System.arraycopy(elementData,?r,
?????????????????????????????????elementData,?w,
?????????????????????????????????size?-?r);
????????????????w?+=?size?-?r;
????????????}
????????????if?(w?!=?size)?{
????????????????for?(int?i?=?w;?i?<?size;?i++)
????????????????????elementData[i]?=?null;
????????????????modCount?+=?size?-?w;
????????????????size?=?w;
????????????????modified?=?true;
????????????}
????????}
????????return?modified;
????}
删除或保留ArrayList中包含Collection c中的的元素,这两个方法都依赖batchRemove(Collection<?> c, boolean complement)实现。
看到这里是该说明一下modCount了,这个是个什么鬼?
其实在add()、remove()、addall()、removerange()及clear()方法都会让modCount增长,在add()及addall()方法的对modCount的操作在ensureCapacityInternal中。 modCount用于记录ArrayList的结构性变化的次数,也用于序列化。
17 writeObject(ObjectOutputStream)
/**
?????*?Save?the?state?of?the?<tt>ArrayList</tt>?instance?to?a?stream?(that
?????*?is,?serialize?it).
?????*
?????*?@serialData?The?length?of?the?array?backing?the?<tt>ArrayList</tt>
?????*?????????????instance?is?emitted?(int),?followed?by?all?of?its?elements
?????*?????????????(each?an?<tt>Object</tt>)?in?the?proper?order.
?????*/
????private?void?writeObject(java.io.ObjectOutputStream?s)
????????throws?java.io.IOException{
????????//?Write?out?element?count,?and?any?hidden?stuff
????????int?expectedModCount?=?modCount;
????????s.defaultWriteObject();
????????//?Write?out?array?length
????????s.writeInt(elementData.length);
????????//?Write?out?all?elements?in?the?proper?order.
????????for?(int?i=0;?i<size;?i++)
????????????s.writeObject(elementData[i]);
????????if?(modCount?!=?expectedModCount)?{
????????????throw?new?ConcurrentModificationException();
????????}
????}
该方法是将ArrayList保存为流,即对modCount,数组长度及元素进行序列化操作。还是个private方法,估计是ArrayList内部使用的。
18 readObject (ObjectOutputStream)
/**
?????*?Reconstitute?the?<tt>ArrayList</tt>?instance?from?a?stream?(that?is,
?????*?deserialize?it).
?????*/
????private?void?readObject(java.io.ObjectInputStream?s)
????????throws?java.io.IOException,?ClassNotFoundException?{
????????//?Read?in?size,?and?any?hidden?stuff
????????s.defaultReadObject();
????????//?Read?in?array?length?and?allocate?array
????????int?arrayLength?=?s.readInt();
????????Object[]?a?=?elementData?=?new?Object[arrayLength];
????????//?Read?in?all?elements?in?the?proper?order.
????????for?(int?i=0;?i<size;?i++)
????????????a[i]?=?s.readObject();
????}
有了writeObject,那么对应就有readObject,将ArrayList反序列化。
虽然洋洋洒洒写了这么多,几乎将源码粘出来了,但还是有个别细节问题模棱两可,比如ArrayList三种遍历方式效率的比较,removeRange为什么是一个保护方法而不能直接使用,内部私有类Itr,ListItr,SubList及其使用等,文章只是浅显地罗列了我们工作中常用的ArrayList的方法和特性,更细节深入的东西留待以后补充。
转载于:https://my.oschina.net/u/2610176/blog/600950
内容总结
以上是互联网集市为您收集整理的JAVA源码学习-ArrayList全部内容,希望文章能够帮你解决JAVA源码学习-ArrayList所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。