java集合框架03——ArrayList和源码分析

本文详细介绍了ArrayList,它是List中常用的动态数组,操作非线程安全。分析了其基于JDK1.7的源码,包括默认容量、自动扩容等。还探讨了三种遍历方式,随机访问效率最高。此外,指出调用toArray()可能出现的异常及解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载https://blog.youkuaiyun.com/eson_15/article/details/51121833

    上一章学习了Collection的架构,并阅读了部分源码,这一章开始,我们将对Collection的具体实现进行详细学习。首先学习List。而ArrayList又是List中最为常用的,因此本章先学习ArrayList。先对ArrayList有个整体的认识,然后学习它的源码,深入剖析ArrayList。

1. ArrayList简介

    首先看看ArrayList与Collection的关系:

    ArrayList的继承关系如下:


 
  1. java.lang.Object

  2. ↳ java.util.AbstractCollection<E>

  3. ↳ java.util.AbstractList<E>

  4. ↳ java.util.ArrayList<E>

  5.  
  6. public class ArrayList<E> extends AbstractList<E>

  7. implements List<E>, 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的构造函数和API

 


 
  1. /****************** ArrayList中的构造函数 ***************/

  2. // 默认构造函数

  3. ArrayList()

  4.  
  5. // capacity是ArrayList的默认容量大小。当由于增加数据导致容量不足时,容量会添加上一次容量大小的一半。

  6. ArrayList(int capacity)

  7.  
  8. // 创建一个包含collection的ArrayList

  9. ArrayList(Collection<? extends E> collection)

  10.  
  11. /****************** ArrayList中的API ********************/

  12. // Collection中定义的API

  13. boolean add(E object)

  14. boolean addAll(Collection<? extends E> collection)

  15. void clear()

  16. boolean contains(Object object)

  17. boolean containsAll(Collection<?> collection)

  18. boolean equals(Object object)

  19. int hashCode()

  20. boolean isEmpty()

  21. Iterator<E> iterator()

  22. boolean remove(Object object)

  23. boolean removeAll(Collection<?> collection)

  24. boolean retainAll(Collection<?> collection)

  25. int size()

  26. <T> T[] toArray(T[] array)

  27. Object[] toArray()

  28. // AbstractCollection中定义的API

  29. void add(int location, E object)

  30. boolean addAll(int location, Collection<? extends E> collection)

  31. E get(int location)

  32. int indexOf(Object object)

  33. int lastIndexOf(Object object)

  34. ListIterator<E> listIterator(int location)

  35. ListIterator<E> listIterator()

  36. E remove(int location)

  37. E set(int location, E object)

  38. List<E> subList(int start, int end)

  39. // ArrayList新增的API

  40. Object clone()

  41. void ensureCapacity(int minimumCapacity)

  42. void trimToSize()

  43. void removeRange(int fromIndex, int toIndex)

    ArrayList包含了两个重要的对象:elementData和size。

    elementData是Object[]类型的数组,它保存了添加到ArrayList中的元素。实际上,elementData是一个动态数组,我们能通过ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity。如果通过不含参数的构造函数来创建ArrayList,则elementData是一个空数组(后面会调整其大小)。elementData数组的大小会根据ArrayList容量的增长而动态的增长,具体见下面的源码。

    size则是动态数组实际的大小。

2. ArrayList源码分析(基于JDK1.7)

        下面通过分析ArrayList的源码更加深入的了解ArrayList原理。由于ArrayList是通过数组实现的,所以源码比较容易理解:


 
  1. package java.util;

  2.  
  3. public class ArrayList<E> extends AbstractList<E>

  4. implements List<E>, RandomAccess, Cloneable, java.io.Serializable

  5. {

  6. //序列版本号

  7. private static final long serialVersionUID = 8683452581122892189L;

  8.  
  9. //默认初始化容量

  10. private static final int DEFAULT_CAPACITY = 10;

  11.  
  12. //空数组,用来实例化不带容量大小的构造函数

  13. private static final Object[] EMPTY_ELEMENTDATA = {};

  14.  
  15. //保存ArrayList中数据的数组

  16. private transient Object[] elementData;

  17.  
  18. //ArrayList中实际数据的数量

  19. private int size;

  20.  
  21. /******************************** Constructor ***********************************/

  22.  
  23. //ArrayList带容量大小的构造函数

  24. public ArrayList(int initialCapacity) {

  25. super();

  26. if (initialCapacity < 0)

  27. throw new IllegalArgumentException("Illegal Capacity: "+

  28. initialCapacity);

  29. this.elementData = new Object[initialCapacity]; //新建一个数组初始化elementData

  30. }

  31.  
  32. //不带参数的构造函数

  33. public ArrayList() {

  34. super();

  35. this.elementData = EMPTY_ELEMENTDATA;//使用空数组初始化elementData

  36. }

  37.  
  38. //用Collection来初始化ArrayList

  39. public ArrayList(Collection<? extends E> c) {

  40. elementData = c.toArray(); //将Collection中的内容转换成数组初始化elementData

  41. size = elementData.length;

  42. // c.toArray might (incorrectly) not return Object[] (see 6260652)

  43. if (elementData.getClass() != Object[].class)

  44. elementData = Arrays.copyOf(elementData, size, Object[].class);

  45. }

  46.  
  47. /********************************* Array size ************************************/

  48.  
  49. //重新“修剪”数组容量大小

  50. public void trimToSize() {

  51. modCount++;

  52. //当ArrayList中的元素个数小于elementData数组大小时,重新修整elementData到size大小

  53. if (size < elementData.length) {

  54. elementData = Arrays.copyOf(elementData, size);

  55. }

  56. }

  57.  
  58. //给数组扩容,该方法是提供给外界调用的,是public的,真正扩容是在下面的private方法里

  59. public void ensureCapacity(int minCapacity) {

  60. int minExpand = (elementData != EMPTY_ELEMENTDATA)

  61. // any size if real element table

  62. ? 0

  63. // larger than default for empty table. It's already supposed to be

  64. // at default size.

  65. : DEFAULT_CAPACITY;

  66.  
  67. if (minCapacity > minExpand) {

  68. ensureExplicitCapacity(minCapacity);

  69. }

  70. }

  71.  
  72. private void ensureCapacityInternal(int minCapacity) {

  73. //如果是个空数组

  74. if (elementData == EMPTY_ELEMENTDATA) {

  75. //取minCapacity和10的较大者

  76. minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

  77. }

  78. //如果数组已经有数据了

  79. ensureExplicitCapacity(minCapacity);

  80. }

  81.  
  82. //确保数组容量大于ArrayList中元素个数

  83. private void ensureExplicitCapacity(int minCapacity) {

  84. modCount++; //将“修改统计数”+1

  85.  
  86. //如果实际数据容量大于数组容量,就给数组扩容

  87. if (minCapacity - elementData.length > 0)

  88. grow(minCapacity);

  89. }

  90.  
  91. //分配的最大数组空间

  92. private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

  93.  
  94. //增大数组空间

  95. private void grow(int minCapacity) {

  96. // overflow-conscious code

  97. int oldCapacity = elementData.length;

  98. int newCapacity = oldCapacity + (oldCapacity >> 1); //在原来容量的基础上加上 oldCapacity/2

  99. if (newCapacity - minCapacity < 0)

  100. newCapacity = minCapacity; //最少保证容量和minCapacity一样

  101. if (newCapacity - MAX_ARRAY_SIZE > 0)

  102. newCapacity = hugeCapacity(minCapacity); //最多不能超过最大容量

  103. // minCapacity is usually close to size, so this is a win:

  104. elementData = Arrays.copyOf(elementData, newCapacity);

  105. }

  106.  
  107. private static int hugeCapacity(int minCapacity) {

  108. if (minCapacity < 0) // overflow

  109. throw new OutOfMemoryError();

  110. return (minCapacity > MAX_ARRAY_SIZE) ?

  111. Integer.MAX_VALUE :

  112. MAX_ARRAY_SIZE;

  113. }

  114.  
  115. //返回ArrayList的实际大小

  116. public int size() {

  117. return size;

  118. }

  119.  
  120. //判断ArrayList是否为空

  121. public boolean isEmpty() {

  122. return size == 0;

  123. }

  124.  
  125. /****************************** Search Operations *************************/

  126.  
  127. //判断ArrayList是否包含Object o

  128. public boolean contains(Object o) {

  129. return indexOf(o) >= 0;

  130. }

  131.  
  132. //正向查找,返回元素的索引值

  133. public int indexOf(Object o) {

  134. if (o == null) {

  135. for (int i = 0; i < size; i++)

  136. if (elementData[i]==null)

  137. return i;

  138. } else {

  139. for (int i = 0; i < size; i++)

  140. if (o.equals(elementData[i]))

  141. return i;

  142. }

  143. return -1;

  144. }

  145.  
  146. //反向查找,返回元素的索引值

  147. public int lastIndexOf(Object o) {

  148. if (o == null) {

  149. for (int i = size-1; i >= 0; i--)

  150. if (elementData[i]==null)

  151. return i;

  152. } else {

  153. for (int i = size-1; i >= 0; i--)

  154. if (o.equals(elementData[i]))

  155. return i;

  156. }

  157. return -1;

  158. }

  159.  
  160. /******************************* Clone *********************************/

  161.  
  162. //克隆函数

  163. public Object clone() {

  164. try {

  165. @SuppressWarnings("unchecked")

  166. ArrayList<E> v = (ArrayList<E>) super.clone();

  167. //将当前ArrayList的全部元素拷贝到v中

  168. v.elementData = Arrays.copyOf(elementData, size);

  169. v.modCount = 0;

  170. return v;

  171. } catch (CloneNotSupportedException e) {

  172. // this shouldn't happen, since we are Cloneable

  173. throw new InternalError();

  174. }

  175. }

  176.  
  177. /********************************* toArray *****************************/

  178.  
  179. /**

  180. * 返回一个Object数组,包含ArrayList中所有的元素

  181. * toArray()方法扮演着array-based和collection-based API之间的桥梁

  182. */

  183. public Object[] toArray() {

  184. return Arrays.copyOf(elementData, size);

  185. }

  186.  
  187. //返回ArrayList的模板数组

  188. @SuppressWarnings("unchecked")

  189. public <T> T[] toArray(T[] a) {

  190. //如果数组a的大小 < ArrayList的元素个数,

  191. //则新建一个T[]数组,大小为ArrayList元素个数,并将“ArrayList”全部拷贝到新数组中。

  192. if (a.length < size)

  193. return (T[]) Arrays.copyOf(elementData, size, a.getClass());

  194.  
  195. //如果数组a的大小 >= ArrayList的元素个数,

  196. //则将ArrayList全部拷贝到新数组a中。

  197. System.arraycopy(elementData, 0, a, 0, size);

  198. if (a.length > size)

  199. a[size] = null;

  200. return a;

  201. }

  202.  
  203. /******************** Positional Access Operations ********************/

  204.  
  205. @SuppressWarnings("unchecked")

  206. E elementData(int index) {

  207. return (E) elementData[index];

  208. }

  209.  
  210. //获取index位置的元素值

  211. public E get(int index) {

  212. rangeCheck(index); //首先判断index的范围是否合法

  213.  
  214. return elementData(index);

  215. }

  216.  
  217. //将index位置的值设为element,并返回原来的值

  218. public E set(int index, E element) {

  219. rangeCheck(index);

  220.  
  221. E oldValue = elementData(index);

  222. elementData[index] = element;

  223. return oldValue;

  224. }

  225.  
  226. //将e添加到ArrayList中

  227. public boolean add(E e) {

  228. ensureCapacityInternal(size + 1); // Increments modCount!!

  229. elementData[size++] = e;

  230. return true;

  231. }

  232.  
  233. //将element添加到ArrayList的指定位置

  234. public void add(int index, E element) {

  235. rangeCheckForAdd(index);

  236.  
  237. ensureCapacityInternal(size + 1); // Increments modCount!!

  238. //将index以及index之后的数据复制到index+1的位置往后,即从index开始向后挪了一位

  239. System.arraycopy(elementData, index, elementData, index + 1,

  240. size - index);

  241. elementData[index] = element; //然后在index处插入element

  242. size++;

  243. }

  244.  
  245. //删除ArrayList指定位置的元素

  246. public E remove(int index) {

  247. rangeCheck(index);

  248.  
  249. modCount++;

  250. E oldValue = elementData(index);

  251.  
  252. int numMoved = size - index - 1;

  253. if (numMoved > 0)

  254. //向左挪一位,index位置原来的数据已经被覆盖了

  255. System.arraycopy(elementData, index+1, elementData, index,

  256. numMoved);

  257. //多出来的最后一位删掉

  258. elementData[--size] = null; // clear to let GC do its work

  259.  
  260. return oldValue;

  261. }

  262.  
  263. //删除ArrayList中指定的元素

  264. public boolean remove(Object o) {

  265. if (o == null) {

  266. for (int index = 0; index < size; index++)

  267. if (elementData[index] == null) {

  268. fastRemove(index);

  269. return true;

  270. }

  271. } else {

  272. for (int index = 0; index < size; index++)

  273. if (o.equals(elementData[index])) {

  274. fastRemove(index);

  275. return true;

  276. }

  277. }

  278. return false;

  279. }

  280.  
  281. //private的快速删除与上面的public普通删除区别在于,没有进行边界判断以及不返回删除值

  282. private void fastRemove(int index) {

  283. modCount++;

  284. int numMoved = size - index - 1;

  285. if (numMoved > 0)

  286. System.arraycopy(elementData, index+1, elementData, index,

  287. numMoved);

  288. elementData[--size] = null; // clear to let GC do its work

  289. }

  290.  
  291. //清空ArrayList,将全部元素置为null

  292. public void clear() {

  293. modCount++;

  294.  
  295. // clear to let GC do its work

  296. for (int i = 0; i < size; i++)

  297. elementData[i] = null;

  298.  
  299. size = 0;

  300. }

  301.  
  302. //将集合C中所有的元素添加到ArrayList中

  303. public boolean addAll(Collection<? extends E> c) {

  304. Object[] a = c.toArray();

  305. int numNew = a.length;

  306. ensureCapacityInternal(size + numNew); // Increments modCount

  307. //在原来数组的后面添加c中所有的元素

  308. System.arraycopy(a, 0, elementData, size, numNew);

  309. size += numNew;

  310. return numNew != 0;

  311. }

  312.  
  313. //从index位置开始,将集合C中所欲的元素添加到ArrayList中

  314. public boolean addAll(int index, Collection<? extends E> c) {

  315. rangeCheckForAdd(index);

  316.  
  317. Object[] a = c.toArray();

  318. int numNew = a.length;

  319. ensureCapacityInternal(size + numNew); // Increments modCount

  320.  
  321. int numMoved = size - index;

  322. if (numMoved > 0)

  323. //将index开始向后的所有数据,向后移动numNew个位置,给新插入的数据腾出空间

  324. System.arraycopy(elementData, index, elementData, index + numNew,

  325. numMoved);

  326. //将集合C中的数据插到刚刚腾出的位置

  327. System.arraycopy(a, 0, elementData, index, numNew);

  328. size += numNew;

  329. return numNew != 0;

  330. }

  331.  
  332. //删除从fromIndex到toIndex之间的数据,不包括toIndex位置的数据

  333. protected void removeRange(int fromIndex, int toIndex) {

  334. modCount++;

  335. int numMoved = size - toIndex;

  336. System.arraycopy(elementData, toIndex, elementData, fromIndex,

  337. numMoved);

  338.  
  339. // clear to let GC do its work

  340. int newSize = size - (toIndex-fromIndex);

  341. for (int i = newSize; i < size; i++) {

  342. elementData[i] = null;

  343. }

  344. size = newSize;

  345. }

  346.  
  347. //范围检测

  348. private void rangeCheck(int index) {

  349. if (index >= size)

  350. throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

  351. }

  352.  
  353. //add和addAll方法中的范围检测

  354. private void rangeCheckForAdd(int index) {

  355. if (index > size || index < 0)

  356. throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

  357. }

  358.  
  359. private String outOfBoundsMsg(int index) {

  360. return "Index: "+index+", Size: "+size;

  361. }

  362.  
  363. //删除ArrayList中所有集合C中包含的数据

  364. public boolean removeAll(Collection<?> c) {

  365. return batchRemove(c, false);

  366. }

  367.  
  368. //删除ArrayList中除了集合C中包含的数据外的其他所有数据

  369. public boolean retainAll(Collection<?> c) {

  370. return batchRemove(c, true);

  371. }

  372.  
  373. //批量删除

  374. private boolean batchRemove(Collection<?> c, boolean complement) {

  375. final Object[] elementData = this.elementData;

  376. int r = 0, w = 0;

  377. boolean modified = false;

  378. try {

  379. for (; r < size; r++)

  380. if (c.contains(elementData[r]) == complement)

  381. elementData[w++] = elementData[r];

  382. } finally {

  383. // Preserve behavioral compatibility with AbstractCollection,

  384. // even if c.contains() throws.

  385. //官方的注释是为了保持和AbstractCollection的兼容性

  386. //我的理解是上面c.contains抛出了异常,导致for循环终止,那么必然会导致r != size

  387. //所以0-w之间是需要保留的数据,同时从w索引开始将剩下没有循环的数据(也就是从r开始的)拷贝回来,也保留

  388. if (r != size) {

  389. System.arraycopy(elementData, r,

  390. elementData, w,

  391. size - r);

  392. w += size - r;

  393. }

  394. //for循环完毕,检测了所有的元素

  395. //0-w之间保存了需要留下的数据,w开始以及后面的数据全部清空

  396. if (w != size) {

  397. // clear to let GC do its work

  398. for (int i = w; i < size; i++)

  399. elementData[i] = null;

  400. modCount += size - w;

  401. size = w;

  402. modified = true;

  403. }

  404. }

  405. return modified;

  406. }

  407.  
  408. /***************************** Writer and Read Object *************************/

  409.  
  410. //java.io.Serializable的写入函数

  411. //将ArrayList的“容量、所有的元素值”都写入到输出流中

  412. private void writeObject(java.io.ObjectOutputStream s)

  413. throws java.io.IOException{

  414. // Write out element count, and any hidden stuff

  415. int expectedModCount = modCount;

  416. s.defaultWriteObject();

  417.  
  418. // Write out size as capacity for behavioural compatibility with clone()

  419. //写入“数组的容量”,保持与clone()的兼容性

  420. s.writeInt(size);

  421.  
  422. //写入“数组的每一个元素”

  423. for (int i=0; i<size; i++) {

  424. s.writeObject(elementData[i]);

  425. }

  426.  
  427. if (modCount != expectedModCount) {

  428. throw new ConcurrentModificationException();

  429. }

  430. }

  431.  
  432. //java.io.Serializable的读取函数:根据写入方式读出

  433. private void readObject(java.io.ObjectInputStream s)

  434. throws java.io.IOException, ClassNotFoundException {

  435. elementData = EMPTY_ELEMENTDATA;

  436.  
  437. // Read in size, and any hidden stuff

  438. s.defaultReadObject();

  439.  
  440. //从输入流中读取ArrayList的“容量”

  441. s.readInt(); // ignored

  442.  
  443. if (size > 0) {

  444. // be like clone(), allocate array based upon size not capacity

  445. ensureCapacityInternal(size);

  446.  
  447. Object[] a = elementData;

  448. //从输入流中将“所有元素值”读出

  449. for (int i=0; i<size; i++) {

  450. a[i] = s.readObject();

  451. }

  452. }

  453. }

  454.  
  455. /******************************** Iterators ************************************/

  456.  
  457. /**

  458. * 该部分的方法重写了AbstractList抽象类中Iterator部分的方法,因为ArrayList继承

  459. * 了AbstractList,基本大同小异,只是这里针对本类的数组,思想与AbstractList一致

  460. * 可以参照上一章Collection架构与源码分析的AbatractList部分

  461. */

  462. public ListIterator<E> listIterator(int index) {

  463. if (index < 0 || index > size)

  464. throw new IndexOutOfBoundsException("Index: "+index);

  465. return new ListItr(index);

  466. }

  467.  
  468. public ListIterator<E> listIterator() {

  469. return new ListItr(0);

  470. }

  471.  
  472. public Iterator<E> iterator() {

  473. return new Itr();

  474. }

  475.  
  476. private class Itr implements Iterator<E> {

  477. int cursor; // index of next element to return

  478. int lastRet = -1; // index of last element returned; -1 if no such

  479. int expectedModCount = modCount;

  480.  
  481. public boolean hasNext() {

  482. return cursor != size;

  483. }

  484.  
  485. @SuppressWarnings("unchecked")

  486. public E next() {

  487. checkForComodification();

  488. int i = cursor;

  489. if (i >= size)

  490. throw new NoSuchElementException();

  491. Object[] elementData = ArrayList.this.elementData;

  492. if (i >= elementData.length)

  493. throw new ConcurrentModificationException();

  494. cursor = i + 1;

  495. return (E) elementData[lastRet = i];

  496. }

  497.  
  498. public void remove() {

  499. if (lastRet < 0)

  500. throw new IllegalStateException();

  501. checkForComodification();

  502.  
  503. try {

  504. ArrayList.this.remove(lastRet);

  505. cursor = lastRet;

  506. lastRet = -1;

  507. expectedModCount = modCount;

  508. } catch (IndexOutOfBoundsException ex) {

  509. throw new ConcurrentModificationException();

  510. }

  511. }

  512.  
  513. final void checkForComodification() {

  514. if (modCount != expectedModCount)

  515. throw new ConcurrentModificationException();

  516. }

  517. }

  518.  
  519. private class ListItr extends Itr implements ListIterator<E> {

  520. ListItr(int index) {

  521. super();

  522. cursor = index;

  523. }

  524.  
  525. public boolean hasPrevious() {

  526. return cursor != 0;

  527. }

  528.  
  529. public int nextIndex() {

  530. return cursor;

  531. }

  532.  
  533. public int previousIndex() {

  534. return cursor - 1;

  535. }

  536.  
  537. @SuppressWarnings("unchecked")

  538. public E previous() {

  539. checkForComodification();

  540. int i = cursor - 1;

  541. if (i < 0)

  542. throw new NoSuchElementException();

  543. Object[] elementData = ArrayList.this.elementData;

  544. if (i >= elementData.length)

  545. throw new ConcurrentModificationException();

  546. cursor = i;

  547. return (E) elementData[lastRet = i];

  548. }

  549.  
  550. public void set(E e) {

  551. if (lastRet < 0)

  552. throw new IllegalStateException();

  553. checkForComodification();

  554.  
  555. try {

  556. ArrayList.this.set(lastRet, e);

  557. } catch (IndexOutOfBoundsException ex) {

  558. throw new ConcurrentModificationException();

  559. }

  560. }

  561.  
  562. public void add(E e) {

  563. checkForComodification();

  564.  
  565. try {

  566. int i = cursor;

  567. ArrayList.this.add(i, e);

  568. cursor = i + 1;

  569. lastRet = -1;

  570. expectedModCount = modCount;

  571. } catch (IndexOutOfBoundsException ex) {

  572. throw new ConcurrentModificationException();

  573. }

  574. }

  575. }

  576.  
  577. public List<E> subList(int fromIndex, int toIndex) {

  578. subListRangeCheck(fromIndex, toIndex, size);

  579. return new SubList(this, 0, fromIndex, toIndex);

  580. }

  581.  
  582. static void subListRangeCheck(int fromIndex, int toIndex, int size) {

  583. if (fromIndex < 0)

  584. throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);

  585. if (toIndex > size)

  586. throw new IndexOutOfBoundsException("toIndex = " + toIndex);

  587. if (fromIndex > toIndex)

  588. throw new IllegalArgumentException("fromIndex(" + fromIndex +

  589. ") > toIndex(" + toIndex + ")");

  590. }

  591.  
  592. private class SubList extends AbstractList<E> implements RandomAccess {

  593. private final AbstractList<E> parent;

  594. private final int parentOffset;

  595. private final int offset;

  596. int size;

  597.  
  598. SubList(AbstractList<E> parent,

  599. int offset, int fromIndex, int toIndex) {

  600. this.parent = parent;

  601. this.parentOffset = fromIndex;

  602. this.offset = offset + fromIndex;

  603. this.size = toIndex - fromIndex;

  604. this.modCount = ArrayList.this.modCount;

  605. }

  606.  
  607. public E set(int index, E e) {

  608. rangeCheck(index);

  609. checkForComodification();

  610. E oldValue = ArrayList.this.elementData(offset + index);

  611. ArrayList.this.elementData[offset + index] = e;

  612. return oldValue;

  613. }

  614.  
  615. public E get(int index) {

  616. rangeCheck(index);

  617. checkForComodification();

  618. return ArrayList.this.elementData(offset + index);

  619. }

  620.  
  621. public int size() {

  622. checkForComodification();

  623. return this.size;

  624. }

  625.  
  626. public void add(int index, E e) {

  627. rangeCheckForAdd(index);

  628. checkForComodification();

  629. parent.add(parentOffset + index, e);

  630. this.modCount = parent.modCount;

  631. this.size++;

  632. }

  633.  
  634. public E remove(int index) {

  635. rangeCheck(index);

  636. checkForComodification();

  637. E result = parent.remove(parentOffset + index);

  638. this.modCount = parent.modCount;

  639. this.size--;

  640. return result;

  641. }

  642.  
  643. protected void removeRange(int fromIndex, int toIndex) {

  644. checkForComodification();

  645. parent.removeRange(parentOffset + fromIndex,

  646. parentOffset + toIndex);

  647. this.modCount = parent.modCount;

  648. this.size -= toIndex - fromIndex;

  649. }

  650.  
  651. public boolean addAll(Collection<? extends E> c) {

  652. return addAll(this.size, c);

  653. }

  654.  
  655. public boolean addAll(int index, Collection<? extends E> c) {

  656. rangeCheckForAdd(index);

  657. int cSize = c.size();

  658. if (cSize==0)

  659. return false;

  660.  
  661. checkForComodification();

  662. parent.addAll(parentOffset + index, c);

  663. this.modCount = parent.modCount;

  664. this.size += cSize;

  665. return true;

  666. }

  667.  
  668. public Iterator<E> iterator() {

  669. return listIterator();

  670. }

  671.  
  672. public ListIterator<E> listIterator(final int index) {

  673. checkForComodification();

  674. rangeCheckForAdd(index);

  675. final int offset = this.offset;

  676.  
  677. return new ListIterator<E>() {

  678. int cursor = index;

  679. int lastRet = -1;

  680. int expectedModCount = ArrayList.this.modCount;

  681.  
  682. public boolean hasNext() {

  683. return cursor != SubList.this.size;

  684. }

  685.  
  686. @SuppressWarnings("unchecked")

  687. public E next() {

  688. checkForComodification();

  689. int i = cursor;

  690. if (i >= SubList.this.size)

  691. throw new NoSuchElementException();

  692. Object[] elementData = ArrayList.this.elementData;

  693. if (offset + i >= elementData.length)

  694. throw new ConcurrentModificationException();

  695. cursor = i + 1;

  696. return (E) elementData[offset + (lastRet = i)];

  697. }

  698.  
  699. public boolean hasPrevious() {

  700. return cursor != 0;

  701. }

  702.  
  703. @SuppressWarnings("unchecked")

  704. public E previous() {

  705. checkForComodification();

  706. int i = cursor - 1;

  707. if (i < 0)

  708. throw new NoSuchElementException();

  709. Object[] elementData = ArrayList.this.elementData;

  710. if (offset + i >= elementData.length)

  711. throw new ConcurrentModificationException();

  712. cursor = i;

  713. return (E) elementData[offset + (lastRet = i)];

  714. }

  715.  
  716. public int nextIndex() {

  717. return cursor;

  718. }

  719.  
  720. public int previousIndex() {

  721. return cursor - 1;

  722. }

  723.  
  724. public void remove() {

  725. if (lastRet < 0)

  726. throw new IllegalStateException();

  727. checkForComodification();

  728.  
  729. try {

  730. SubList.this.remove(lastRet);

  731. cursor = lastRet;

  732. lastRet = -1;

  733. expectedModCount = ArrayList.this.modCount;

  734. } catch (IndexOutOfBoundsException ex) {

  735. throw new ConcurrentModificationException();

  736. }

  737. }

  738.  
  739. public void set(E e) {

  740. if (lastRet < 0)

  741. throw new IllegalStateException();

  742. checkForComodification();

  743.  
  744. try {

  745. ArrayList.this.set(offset + lastRet, e);

  746. } catch (IndexOutOfBoundsException ex) {

  747. throw new ConcurrentModificationException();

  748. }

  749. }

  750.  
  751. public void add(E e) {

  752. checkForComodification();

  753.  
  754. try {

  755. int i = cursor;

  756. SubList.this.add(i, e);

  757. cursor = i + 1;

  758. lastRet = -1;

  759. expectedModCount = ArrayList.this.modCount;

  760. } catch (IndexOutOfBoundsException ex) {

  761. throw new ConcurrentModificationException();

  762. }

  763. }

  764.  
  765. final void checkForComodification() {

  766. if (expectedModCount != ArrayList.this.modCount)

  767. throw new ConcurrentModificationException();

  768. }

  769. };

  770. }

  771.  
  772. public List<E> subList(int fromIndex, int toIndex) {

  773. subListRangeCheck(fromIndex, toIndex, size);

  774. return new SubList(this, offset, fromIndex, toIndex);

  775. }

  776.  
  777. private void rangeCheck(int index) {

  778. if (index < 0 || index >= this.size)

  779. throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

  780. }

  781.  
  782. private void rangeCheckForAdd(int index) {

  783. if (index < 0 || index > this.size)

  784. throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

  785. }

  786.  
  787. private String outOfBoundsMsg(int index) {

  788. return "Index: "+index+", Size: "+this.size;

  789. }

  790.  
  791. private void checkForComodification() {

  792. if (ArrayList.this.modCount != this.modCount)

  793. throw new ConcurrentModificationException();

  794. }

  795. }

  796. }

    总结一下:

    1). ArrayList实际上是通过一个数组去保存数据的,当我们构造ArrayList时,如果使用默认构造函数,最后ArrayList的默认容量大小是10。

    2). 当ArrayList容量不足以容纳全部元素时,ArrayList会自动扩张容量,新的容量 = 原始容量 + 原始容量 / 2。

    3). ArrayList的克隆函数,即是将全部元素克隆到一个数组中。

    4. ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写出“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。

3. ArrayList遍历方式

    ArrayList支持三种遍历方式,下面我们逐个讨论:

    1). 通过迭代器遍历。即Iterator迭代器。


 
  1. Integer value = null;

  2. Iterator it = list.iterator();

  3. while (it.hasNext()) {

  4. value = (Integer)it.next();

  5. }

    2). 随机访问,通过索引值去遍历。由于ArrayList实现了RandomAccess接口,所以它支持通过索引值去随机访问元素。


 
  1. Integer value = null;

  2. int size = list.size();

  3. for (int i = 0; i < size; i++) {

  4. value = (Integer)list.get(i);

  5. }

   3). 通过for循环遍历。


 
  1. Integer value = null;

  2. for (Integer integ : list) {

  3. value = integ;

  4. }

        下面写了一个测试用例,比较这三种遍历方式的效率:


 
  1. import java.util.*;

  2.  
  3. /*

  4. * @description ArrayList三种遍历方式效率的测试

  5. * @author eson_15

  6. */

  7. public class ArrayListRandomAccessTest {

  8.  
  9. public static void main(String[] args) {

  10. List<Integer> list = new ArrayList<Integer>();

  11. for (int i=0; i<500000; i++)

  12. list.add(i);

  13. isRandomAccessSupported(list);//判断是否支持RandomAccess

  14. iteratorThroughRandomAccess(list) ;

  15. iteratorThroughIterator(list) ;

  16. iteratorThroughFor(list) ;

  17.  
  18. }

  19.  
  20. private static void isRandomAccessSupported(List<Integer> list) {

  21. if (list instanceof RandomAccess) {

  22. System.out.println("RandomAccess implemented!");

  23. } else {

  24. System.out.println("RandomAccess not implemented!");

  25. }

  26.  
  27. }

  28.  
  29. public static void iteratorThroughRandomAccess(List<Integer> list) {

  30.  
  31. long startTime;

  32. long endTime;

  33. startTime = System.currentTimeMillis();

  34. for (int i=0; i<list.size(); i++) {

  35. list.get(i);

  36. }

  37. endTime = System.currentTimeMillis();

  38. long interval = endTime - startTime;

  39. System.out.println("RandomAccess遍历时间:" + interval+" ms");

  40. }

  41.  
  42. public static void iteratorThroughIterator(List<Integer> list) {

  43.  
  44. long startTime;

  45. long endTime;

  46. startTime = System.currentTimeMillis();

  47. for(Iterator<Integer> it = list.iterator(); it.hasNext(); ) {

  48. it.next();

  49. }

  50. endTime = System.currentTimeMillis();

  51. long interval = endTime - startTime;

  52. System.out.println("Iterator遍历时间:" + interval+" ms");

  53. }

  54.  
  55.  
  56. @SuppressWarnings("unused")

  57. public static void iteratorThroughFor(List<Integer> list) {

  58.  
  59. long startTime;

  60. long endTime;

  61. startTime = System.currentTimeMillis();

  62. for(Object obj : list)

  63. ;

  64. endTime = System.currentTimeMillis();

  65. long interval = endTime - startTime;

  66. System.out.println("For循环遍历时间:" + interval+" ms");

  67. }

  68. }

    每次执行的结果会有一点点区别,在这里我统计了6次执行结果,见下表:

 

 

RandomAccess(ms)

Iterator(ms)

For(ms)

第一次

5

8

7

第二次

4

7

7

第三次

5

8

10

第四次

5

7

6

第五次

5

8

7

第六次

5

7

6

平均

4.8

7.5

7.1

    由此可见,遍历ArrayList时,使用随机访问(即通过索引号访问)效率最高,而使用迭代器的效率最低。

 

4. toArray()异常问题

    当我们调用ArrayList中的toArray()方法时,可能会遇到"java.lang.ClassCastException"异常的情况,下面来讨论下出现的原因:

    ArrayList中提供了2个toArray()方法:


 
  1. Object[] toArray()

  2. <T> T[] toArray(T[] contents)

    调用toArray()函数会抛出"java.lang.ClassCastException"异常,但是调用toArray(T[] contents)能正常返回T[]。toArray()会抛出异常是因为toArray()返回的是Object[]数组,将Object[]转换为其它类型(比如将Object[]转换为Integer[])则会抛出"java.lang.ClassCastException"异常,因为java不支持向下转型。解决该问题的办法是调用<T> T[] toArray(T[] contents),而不是Object[] toArray()。

    调用<T> T[] toArray(T[] contents)返回T[]可以通过以下几种方式实现:


 
  1. // toArray(T[] contents)调用方式一

  2. public static Integer[] vectorToArray1(ArrayList<Integer> v) {

  3. Integer[] newText = new Integer[v.size()];

  4. v.toArray(newText);

  5. return newText;

  6. }

  7.  
  8. // toArray(T[] contents)调用方式二。<span style="color:#FF6666;">最常用!</span>

  9. public static Integer[] vectorToArray2(ArrayList<Integer> v) {

  10. Integer[] newText = (Integer[])v.toArray(new Integer[v.size()]);

  11. return newText;

  12. }

  13.  
  14. // toArray(T[] contents)调用方式三

  15. public static Integer[] vectorToArray3(ArrayList<Integer> v) {

  16. Integer[] newText = new Integer[v.size()];

  17. Integer[] newStrings = (Integer[])v.toArray(newText);

  18. return newStrings;

  19. }

    三种方式都大同小异。

    ArrayList源码就讨论这么多,如有错误,欢迎留言指正~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值