第1部分 ArrayList介绍

ArrayList简介

  1. Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)
  2.  
  3. The size, isEmpty, get, set, iterator, and listIterator operations run in constant time. The add operation runs in amortized constant time, that is, adding n elements requires O(n) time. All of the other operations run in linear time (roughly speaking). The constant factor is low compared to that for the LinkedList implementation.
  4.  
  5. Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.
  6.  
  7. An application can increase the capacity of an ArrayList instance before adding a large number of elements using the ensureCapacity operation. This may reduce the amount of incremental reallocation.
  8.  
  9. Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list:
  10.  
  11. List list = Collections.synchronizedList(new ArrayList(...));
  12.  
  13. The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
  14.  
  15. Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

ArrayList是一个动态数组容器类,会自动扩容。

  1. 以数组实现。节约空间,但数组有容量限制。超出限制时会增加50%容量(新容量是原来容量的1.5倍),用System.arraycopy()复制到新的数组,因此最好能给出数组大小的预估值(这个是好的编程习惯)。默认第一次插入元素时创建大小为10的数组。
  2.  
  3. 按数组下标访问元素—get(i)/set(i,e) 的性能很高,这是数组的基本优势。
  4.  
  5. 直接在数组末尾加入元素—add(e)的性能也高,但如果按下标插入、删除元素—add(i,e), remove(i), remove(e),则要用System.arraycopy()来移动部分受影响的元素,性能就变差了,这是基本劣势。

ArrayList中的操作不是线程安全的!在多线程中可以选择Vector或者CopyOnWriteArrayList。

来看一段简单的代码:

  1. public class Test {
  2. public static void main(String[] args) {
  3. List<String> strList = new ArrayList<String>();
  4. strList.add("语文:99");
  5. strList.add("数学:98");
  6. strList.add("英语:100");
  7. strList.remove(0);
  8. }
  9. }

在执行这四条语句时,是这么变化的:

其中,add操作将元素放在数组的末尾,remove(0)操作可以理解为删除index为0的节点,并将后面元素移到0处

第2部分 ArrayList数据结构

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

(1)elementData是Object[]类型的数组,它保存了添加到ArrayList中的元素。

(2)size则是动态数组的实际元素大小。

  1. private static final int DEFAULT_CAPACITY = ;
  2.  
  3. private static final Object[] EMPTY_ELEMENTDATA = {};
  4.  
  5. private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  6.  
  7. transient Object[] elementData; // non-private to simplify nested class access
  8.  
  9. private int size;

第3部分 ArrayList源码api解析

3.1 add()

当我们在ArrayList中增加元素的时候,会使用add函数。他会将元素放到末尾。具体实现如下:

  1. /**
  2. * Appends the specified element to the end of this list.*/
  3. public boolean add(E e) {
  4. ensureCapacityInternal(size + 1); // Increments modCount!!
  5. elementData[size++] = e;
  6. return true;
  7. }

我们可以看到他的实现其实最核心的内容就是ensureCapacityInternal。这个函数其实就是自动扩容机制的核心。我们依次来看一下他的具体实现

  1. private void ensureCapacityInternal(int minCapacity) {
  2. if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
  3. minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  4. }
  5. ensureExplicitCapacity(minCapacity);
  6. }
  7.  
  8. private void ensureExplicitCapacity(int minCapacity) {
  9. modCount++;
  10. // overflow-conscious code
  11. if (minCapacity - elementData.length > 0)
  12. grow(minCapacity);
  13. }
  14. private void grow(int minCapacity) {
  15. // overflow-conscious code
  16. int oldCapacity = elementData.length;
  17. // 扩展为原来的1.5倍
  18. int newCapacity = oldCapacity + (oldCapacity >> 1);
  19. if (newCapacity - minCapacity < 0)
  20. newCapacity = minCapacity;
  21. if (newCapacity - MAX_ARRAY_SIZE > 0)
  22. newCapacity = hugeCapacity(minCapacity);
  23. // minCapacity is usually close to size, so this is a win:
  24. elementData = Arrays.copyOf(elementData, newCapacity);
  25. }
  26.  
  27. private static int hugeCapacity(int minCapacity) {
  28. if (minCapacity < 0) // overflow
  29. throw new OutOfMemoryError();
  30. return (minCapacity > MAX_ARRAY_SIZE) ?
  31. Integer.MAX_VALUE :
  32. MAX_ARRAY_SIZE;
  33. }
  34.  
  35. public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
  36. @SuppressWarnings("unchecked")
  37. T[] copy = ((Object)newType == (Object)Object[].class)
  38. ? (T[]) new Object[newLength]
  39. : (T[]) Array.newInstance(newType.getComponentType(), newLength);
  40. System.arraycopy(original, 0, copy, 0,
  41. Math.min(original.length, newLength));
  42. return copy;
  43. }

也就是说,当增加数据的时候,如果ArrayList的大小已经不满足需求时,那么就将数组变为原长度的1.5倍,之后的操作就是把老的数组拷到新的数组里面。例如,默认的数组大小是10,也就是说当我们add 10个元素之后,再进行一次add时,就会发生自动扩容,数组长度由10变为了15具体情况如下所示:

总结
(01)ArrayList实际上是通过一个数组去保存数据的。当我们构造ArrayList时;若使用默认构造函数,则ArrayList的默认容量大小是10
(02)当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=原始容量x3/2

3.2 set()和get()

ArrayList的set和get函数就比较简单了,先做index检查,然后执行赋值或访问操作:

  1. /**
  2. * Replaces the element at the specified position in this list with
  3. * the specified element.*/
  4. public E set(int index, E element) {
  5. rangeCheck(index);
  6.  
  7. E oldValue = elementData(index);
  8. elementData[index] = element;
  9. return oldValue;
  10. }
  1. /**
  2. * Returns the element at the specified position in this list.*/
  3. public E get(int index) {
  4. rangeCheck(index);
  5.  
  6. return elementData(index);
  7. }
  1. /**
  2. * Checks if the given index is in range. If not, throws an appropriate
  3. * runtime exception.
  4. */
  5. private void rangeCheck(int index) {
  6. if (index >= size)
  7. throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
  8. }

3.3 remove()

  1. /**
  2. * Removes the element at the specified position in this list.
  3. * Shifts any subsequent elements to the left (subtracts one from their
  4. * indices).*/
  5. public E remove(int index) {
  6. rangeCheck(index);
  7. modCount++;
  8. E oldValue = elementData(index);
  9.  
  10. int numMoved = size - index - 1;
  11. if (numMoved > 0)
  12. // 把后面的往前移
  13. System.arraycopy(elementData, index+1, elementData, index,
  14. numMoved);
  15. // 把最后的置null
  16. elementData[--size] = null; // clear to let GC do its work
  17.  
  18. return oldValue;
  19. }
  1. /**
  2. * Removes all of the elements from this list. The list will
  3. * be empty after this call returns.
  4. */
  5. public void clear() {
  6. modCount++;
  7.  
  8. // clear to let GC do its work
  9. for (int i = 0; i < size; i++)
  10. elementData[i] = null;
  11.  
  12. size = 0;
  13. }

第4部分 ArrayList遍历方式

ArrayList支持3种遍历方式

(01)第一种,通过迭代器遍历。即通过Iterator去遍历。

  1. public class Test {
  2. public static void main(String[] args) {
  3. List<Integer> list = new ArrayList<Integer>();
  4. list.add(123);
  5. list.add(456);
  6. list.add(789);
  7. Iterator iter = list.iterator();
  8. while (iter.hasNext()) {
  9. Integer value = (Integer) iter.next();
  10. System.out.println(value);
  11. }
  12. }
  13. }

(02) 第二种,随机访问,通过索引值去遍历。
由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。

  1. public class Test {
  2. public static void main(String[] args) {
  3. List<Integer> list = new ArrayList<Integer>();
  4. list.add(123);
  5. list.add(456);
  6. list.add(789);
  7. int size = list.size();
  8. for (int i=0; i<size; i++) {
  9. Integer value = list.get(i);
  10. System.out.println(value);
  11. }
  12. }
  13. }

(03) 第三种,for循环遍历。如下:

  1. public class Test {
  2. public static void main(String[] args) {
  3. List<Integer> list = new ArrayList<Integer>();
  4. list.add(123);
  5. list.add(456);
  6. list.add(789);
  7. for (Integer integer : list) {
  8. Integer value = integer;
  9. System.out.println(value);
  10. }
  11. }
  12. }

第5部分 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不支持向下转型。具体的可以参考前面ArrayList.java的源码介绍部分的toArray()。
解决该问题的办法是调用<T> T[] toArray(T[] contents) , 而不是Object[] toArray()。

调用 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)调用方式二。最常用!
  9. public static Integer[] vectorToArray2(ArrayList<Integer> v) {
  10. Integer[] newText = (Integer[])v.toArray(new Integer[0]);
  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. }

参考:

http://www.cnblogs.com/skywang12345/p/3308556.html

Class ArrayList
ArrayList其实就那么一回事儿之源码浅析
关于ArrayList

@ArrayList剖析的更多相关文章

  1. 基于JDK1.8的ArrayList剖析

    前言 本文是基于JDK1.8的ArrayList进行分析的.本文大概从以下几个方面来分析ArrayList这个数据结构 构造方法 add方法 扩容 remove方法 (一)构造方法 /** * Con ...

  2. Java 中Iterator 、Vector、ArrayList、List 使用深入剖析

    标签:Iterator Java List ArrayList Vector 线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些 ...

  3. Java 集合框架 ArrayList 源码剖析

    总体介绍 ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现.除该类未实现同步外,其余跟Vector大致相同.每个ArrayL ...

  4. ArrayList源码剖析

    ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线 ...

  5. 转:【Java集合源码剖析】ArrayList源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/35568011   本篇博文参加了CSDN博文大赛,如果您觉得这篇博文不错,希望您能帮我投一 ...

  6. 【java集合框架源码剖析系列】java源码剖析之ArrayList

    注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 本博客将从源码角度带领大家学习关于ArrayList的知识. 一ArrayList类的定义: public class Arr ...

  7. 【Java集合源代码剖析】ArrayList源代码剖析

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/mmc_maodun/article/details/35568011 转载请注明出处:http:// ...

  8. Java ArrayList源码剖析

    转自: Java ArrayList源码剖析 总体介绍 ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null元素,底层通过数组实现.除该类未实现同步外 ...

  9. Java 中 Vector、ArrayList、List 使用深入剖析

    线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以 ...

随机推荐

  1. ECshop语言包lang的加载原理

    当前使用的ecshop的版本:2.7.3,ecshop 2.7.3版本的网店系统的语言包的位置是ecshop文件下 languages/xxx/   其中的xxx表示各种语言的文件夹,里面存放指定语言 ...

  2. CSU训练分类

    √√第一部分 基础算法(#10023 除外) 第 1 章 贪心算法 √√#10000 「一本通 1.1 例 1」活动安排 √√#10001 「一本通 1.1 例 2」种树 √√#10002 「一本通 ...

  3. 【原创】MySQL5.7.18(ptmalloc VS tcmalloc VS jemalloc)性能测试

    ptmalloc(glibc的malloc)是Linux提供的内存分配管理模块,目前我们MySQL默认使用的内存分配模块. tcmalloc是Google提供的内存分配管理模块. jemalloc是F ...

  4. 机器学习之路:python 集成回归模型 随机森林回归RandomForestRegressor 极端随机森林回归ExtraTreesRegressor GradientBoostingRegressor回归 预测波士顿房价

    python3 学习机器学习api 使用了三种集成回归模型 git: https://github.com/linyi0604/MachineLearning 代码: from sklearn.dat ...

  5. 从Table 表中取出第 m 条到第 n 条的记录

    * FROM Table id FROM Table )) --从TABLE表中取出第m到n条记录 (Exists版本) * FROM TABLE AS a WHERE Not Exists ( * ...

  6. BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡 广义后缀自动机 后缀自动机 字符串

    https://www.lydsy.com/JudgeOnline/problem.php?id=3926 广义后缀自动机是一种可以处理好多字符串的一种数据结构(不像后缀自动机只有处理一到两种的时候比 ...

  7. BZOJ 4605 崂山白花蛇草水(权值线段树+KD树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4605 [题目大意] 操作 1 x y k 表示在点(x,y)上放置k个物品, 操作 2 ...

  8. 【SPFA】POJ1860-Currency Exchange

    [题目大意] 给出每两种货币之间交换的手续费和汇率,求出从当前货币s开始交换,能否赚. [思路] 反向运用SPFA,判断是否有正环.每次队首元素出队之后,判断一下到源点s的距离是否增大,增大则返回tr ...

  9. 【洛谷】2324:[SCOI2005]骑士精神【IDA*】

    P2324 [SCOI2005]骑士精神 题目描述 输入输出格式 输入格式: 第一行有一个正整数T(T<=10),表示一共有N组数据.接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,* ...

  10. Java_模拟comet的实现

    本文没有使用任何comet服务器, 只是利用tomcat模拟实现了一下comet, 不是真正的comet哦,因为不会有这样的应用场景, 只是模拟实现, 仅供参考. 一. 需求. 实现将服务端的时间推送 ...