第1部分 ArrayList介绍

ArrayList简介

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.)

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.

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.

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.

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:

   List list = Collections.synchronizedList(new ArrayList(...));

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.

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是一个动态数组容器类,会自动扩容。

以数组实现。节约空间,但数组有容量限制。超出限制时会增加50%容量(新容量是原来容量的1.5倍),用System.arraycopy()复制到新的数组,因此最好能给出数组大小的预估值(这个是好的编程习惯)。默认第一次插入元素时创建大小为10的数组。

按数组下标访问元素—get(i)/set(i,e) 的性能很高,这是数组的基本优势。

直接在数组末尾加入元素—add(e)的性能也高,但如果按下标插入、删除元素—add(i,e), remove(i), remove(e),则要用System.arraycopy()来移动部分受影响的元素,性能就变差了,这是基本劣势。

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

来看一段简单的代码:

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

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

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

第2部分 ArrayList数据结构

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

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

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

private static final int DEFAULT_CAPACITY = ;

private static final Object[] EMPTY_ELEMENTDATA = {};

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

transient Object[] elementData; // non-private to simplify nested class access

private int size;

第3部分 ArrayList源码api解析

3.1 add()

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

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

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

private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
} private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 扩展为原来的1.5倍
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;
} public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}

也就是说,当增加数据的时候,如果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检查,然后执行赋值或访问操作:

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

3.3 remove()

/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).*/
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);
// 把最后的置null
elementData[--size] = null; // clear to let GC do its work return oldValue;
}
/**
* Removes all of the elements from this list. The list will
* be empty after this call returns.
*/
public void clear() {
modCount++; // clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null; size = 0;
}

第4部分 ArrayList遍历方式

ArrayList支持3种遍历方式

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

public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(123);
list.add(456);
list.add(789);
Iterator iter = list.iterator();
while (iter.hasNext()) {
Integer value = (Integer) iter.next();
System.out.println(value);
}
}
}

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

public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(123);
list.add(456);
list.add(789);
int size = list.size();
for (int i=0; i<size; i++) {
Integer value = list.get(i);
System.out.println(value);
}
}
}

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

public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(123);
list.add(456);
list.add(789);
for (Integer integer : list) {
Integer value = integer;
System.out.println(value);
}
}
}

第5部分 toArray()异常

当我们调用ArrayList中的toArray(),可能遇到过抛出"java.lang.ClassCastException"异常的情况。下面我们说说这是怎么回事。

ArrayList提供了2个toArray()函数:

Object[] toArray()
<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[]的可以通过以下几种方式实现。

// toArray(T[] contents)调用方式一
public static Integer[] vectorToArray1(ArrayList<Integer> v) {
Integer[] newText = new Integer[v.size()];
v.toArray(newText);
return newText;
} // toArray(T[] contents)调用方式二。最常用!
public static Integer[] vectorToArray2(ArrayList<Integer> v) {
Integer[] newText = (Integer[])v.toArray(new Integer[0]);
return newText;
} // toArray(T[] contents)调用方式三
public static Integer[] vectorToArray3(ArrayList<Integer> v) {
Integer[] newText = new Integer[v.size()];
Integer[] newStrings = (Integer[])v.toArray(newText);
return newStrings;
}

参考:

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

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

ArrayList源代码深入剖析的更多相关文章

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

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

  2. ArrayList源码剖析与代码实测

    ArrayList源码剖析与代码实测(基于OpenJdk14) 目录 ArrayList源码剖析与代码实测(基于OpenJdk14) 继承关系 从构造函数开始 从add方法深入 / 数组的扩容 其他的 ...

  3. [Java] List / ArrayList - 源代码学习笔记

    在阅读 List / ArrayList 源代码过程中,做了下面的笔记. LinkedList 的笔记较多,放到了另一篇博文 LinkedList / Queue- 源代码学习笔记 List List ...

  4. ArrayList源码剖析

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

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

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

  6. Java ArrayList源码剖析

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

  7. Java集合源码剖析——ArrayList源码剖析

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

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

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

  9. javase基础回顾(一)ArrayList深入解析 解读ArrayList源代码(JDK1.8.0_92)

    我们在学习这一块内容时需要注意的一个问题是 集合中存放的依然是对象的引用而不是对象本身. List接口扩展了Collection并声明存储一系列元素的类集的特性.使用一个基于零的下标,元素可以通过它们 ...

随机推荐

  1. ios版弹珠游戏源码

    这个是我们比较喜欢玩的一直小游戏的,ios版弹珠游戏源码,该游戏源码来着IOS教程网其他网友提供上传的,大家可以了解一下吧. nore_js_op>     <ignore_js_op&g ...

  2. KnockoutJS(4)-控制文本和外观绑定

    控制文本和外观绑定 依赖关系:除了Knockout核心库之外,无依赖关系. 类别 目的 Visible绑定 Visible绑定通过绑定一个值来确定DOM元素显示或隐藏 Text绑定 Text绑定主要是 ...

  3. [转]SET NOCOUNT ON

    ref: http://www.cnblogs.com/jayleke/archive/2010/07/10/1774758.html 在存储过程,触发器中,经常用到SET NOCOUNT ON: 作 ...

  4. Transact-SQL 存储过程(c#调用执行)

    1. Microsoft SQL Server Management Studio 中创建 存储过程 1.1 借助模板资源管理器中的Stored Procedure模板进行修改创建 1.2 直接新建查 ...

  5. javascript event兼容IE和FF

    事件对象在IE和FF下的兼容写法 function abc(event){ var e=event||window.event; //键盘码的捕获 var key=e.which||e.keyCode ...

  6. Oracle SQL的硬解析、软解析、软软解析

    Oracle中每条sql在执行前都要解析,解析分为硬解析.软解析.软软解析. Oracle会缓存DML语句,相同的DML语句会进行软解析.但不会缓存DDL语句,所以DDL每次都做硬解析.硬解析是一个很 ...

  7. WebApi中帮助页Description的中文显示

    转自:http://edi.wang/post/2013/10/28/auto-generate-help-document-aspnet-webapi 我选择Web API的一个重要原因就是因为可以 ...

  8. UITableView自定义单元格

    随手笔记: RootViewController代码 #import "RootViewController.h" #import "AddressContact.h&q ...

  9. Multi-Device Hybrid Apps (Preview)

    Today, we released a preview of Visual Studio tooling support for Apache Cordova http://msdn.microso ...

  10. SwfUpload vs里运行可以上传文件,放到iis上上传就报404错误。

    网上的答案都是说swfupload 的upload_url 路径要设置成绝对路径,但是我也设置了,但是还是不行,然后又找了方法,终于找到了,点击这里查看 解决办法: <system.webSer ...