版权声明:本文为博主原创文章,未经博主同意不得转载。

https://blog.csdn.net/mmc_maodun/article/details/35568011

转载请注明出处:http://blog.csdn.net/ns_code/article/details/35568011


本篇博文參加了CSDN博文大赛,假设您认为这篇博文不错。希望您能帮我投一票。谢谢!

投票地址:http://vote.blog.csdn.net/Article/Details?

articleid=35568011


ArrayList简单介绍

    ArrayList是基于数组实现的。是一个动态数组,其容量能自己主动增长,相似于C语言中的动态申请内存,动态增长内存。

    ArrayList不是线程安全的,仅仅能用在单线程环境下,多线程环境下能够考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也能够使用concurrent并发包下的CopyOnWriteArrayList类。

    ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持高速随机訪问,实际上就是通过下标序号进行高速訪问,实现了Cloneable接口。能被克隆。

ArrayList源代码剖析

    ArrayList的源代码例如以下(加入了比較具体的凝视):

package java.util;  

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
// 序列版本号号
private static final long serialVersionUID = 8683452581122892189L; // ArrayList基于该数组实现,用该数组保存数据
private transient Object[] elementData; // ArrayList中实际数据的数量
private int size; // ArrayList带容量大小的构造函数。
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
// 新建一个数组
this.elementData = new Object[initialCapacity];
} // ArrayList无參构造函数。默认容量是10。
public ArrayList() {
this(10);
} // 创建一个包括collection的ArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} // 将当前容量值设为实际元素个数
public void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (size < oldCapacity) {
elementData = Arrays.copyOf(elementData, size);
}
} // 确定ArrarList的容量。 // 若ArrayList的容量不足以容纳当前的所有元素,设置 新的容量=“(原始容量x3)/2 + 1”
public void ensureCapacity(int minCapacity) {
// 将“改动统计数”+1,该变量主要是用来实现fail-fast机制的
modCount++;
int oldCapacity = elementData.length;
// 若当前容量不足以容纳当前的元素个数,设置 新的容量=“(原始容量x3)/2 + 1”
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
//假设还不够,则直接将minCapacity设置为当前容量
if (newCapacity < minCapacity)
newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);
}
} // 加入元素e
public boolean add(E e) {
// 确定ArrayList的容量大小
ensureCapacity(size + 1); // Increments modCount!!
// 加入e到ArrayList中
elementData[size++] = e;
return true;
} // 返回ArrayList的实际大小
public int size() {
return size;
} // ArrayList是否包括Object(o)
public boolean contains(Object o) {
return indexOf(o) >= 0;
} //返回ArrayList是否为空
public boolean isEmpty() {
return size == 0;
} // 正向查找,返回元素的索引值
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;
} // 反向查找,返回元素的索引值
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;
} // 反向查找(从数组末尾向開始查找),返回元素(o)的索引值
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;
} // 返回ArrayList的Object数组
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
} // 返回ArrayList元素组成的数组
public <T> T[] toArray(T[] a) {
// 若数组a的大小 < ArrayList的元素个数;
// 则新建一个T[]数组,数组大小是“ArrayList的元素个数”,并将“ArrayList”所有复制到新数组中
if (a.length < size)
return (T[]) Arrays.copyOf(elementData, size, a.getClass()); // 若数组a的大小 >= ArrayList的元素个数;
// 则将ArrayList的所有元素都复制到数组a中。
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
} // 获取index位置的元素值
public E get(int index) {
RangeCheck(index); return (E) elementData[index];
} // 设置index位置的值为element
public E set(int index, E element) {
RangeCheck(index); E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
} // 将e加入到ArrayList中
public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
} // 将e加入到ArrayList的指定位置
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size); ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
} // 删除ArrayList指定位置的元素
public E remove(int index) {
RangeCheck(index); modCount++;
E oldValue = (E) 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;
} // 删除ArrayList的指定元素
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;
} // 高速删除第index个元素
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
// 从"index+1"開始。用后面的元素替换前面的元素。
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 将最后一个元素设为null
elementData[--size] = null; // Let gc do its work
} // 删除元素
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
// 便利ArrayList。找到“元素o”,则删除。并返回true。
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
} // 清空ArrayList。将所有的元素设为null
public void clear() {
modCount++; for (int i = 0; i < size; i++)
elementData[i] = null; size = 0;
} // 将集合c追加到ArrayList中
public boolean addAll(Collection<? extends E> 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;
} // 从index位置開始,将集合c加入到ArrayList
public boolean addAll(int index, Collection<? extends E> c) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: " + index + ", Size: " + size); Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved); System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
} // 删除fromIndex到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)
elementData[--size] = null;
} private void RangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
} // 克隆函数
public Object clone() {
try {
ArrayList<E> v = (ArrayList<E>) super.clone();
// 将当前ArrayList的所有元素复制到v中
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();
}
} // java.io.Serializable的写入函数
// 将ArrayList的“容量,所有的元素值”都写入到输出流中
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject(); // 写入“数组的容量”
s.writeInt(elementData.length); // 写入“数组的每个元素”
for (int i=0; i<size; i++)
s.writeObject(elementData[i]); if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
} } // java.io.Serializable的读取函数:依据写入方式读出
// 先将ArrayList的“容量”读出,然后将“所有的元素值”读出
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject(); // 从输入流中读取ArrayList的“容量”
int arrayLength = s.readInt();
Object[] a = elementData = new Object[arrayLength]; // 从输入流中将“所有的元素值”读出
for (int i=0; i<size; i++)
a[i] = s.readObject();
}
}

几点总结

    关于ArrayList的源代码。给出几点比較重要的总结:

    1、注意其三个不同的构造方法。无參构造方法构造的ArrayList的容量默认为10,带有Collection參数的构造方法。将Collection转化为数组赋给ArrayList的实现数组elementData。

    2、注意扩充容量的方法ensureCapacity。ArrayList在每次添加元素(可能是1个,也可能是一组)时,都要调用该方法来确保足够的容量。当容量不足以容纳当前的元素个数时。就设置新的容量为旧的容量的1.5倍加1。假设设置后的新容量还不够,则直接新容量设置为传入的參数(也就是所需的容量)。而后用Arrays.copyof()方法将元素复制到新的数组(详见以下的第3点)。从中能够看出,当容量不够时。每次添加元素,都要将原来的元素复制到一个新的数组中,非常之耗时。也因此建议在事先能确定元素数量的情况下。才使用ArrayList,否则建议使用LinkedList。

    3、ArrayList的实现中大量地调用了Arrays.copyof()和System.arraycopy()方法。我们有必要对这两个方法的实现做下深入的了解。

    首先来看Arrays.copyof()方法。

它有非常多个重载的方法,但实现思路都是一样的。我们来看泛型版本号的源代码:

    public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}

    非常明显调用了还有一个copyof方法。该方法有三个參数。最后一个參数指明要转换的数据的类型。其源代码例如以下:

    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
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;
}

    这里能够非常明显地看出。该方法实际上是在其内部又创建了一个长度为newlength的数组,调用System.arraycopy()方法,将原来数组中的元素复制到了新的数组中。

    以下来看System.arraycopy()方法。

该方法被标记了native,调用了系统的C/C++代码,在JDK中是看不到的,但在openJDK中能够看到其源代码。

该函数实际上终于调用了C语言的memmove()函数,因此它能够保证同一个数组内元素的正确复制和移动,比一般的复制方法的实现效率要高非常多,非常适合用来批量处理数组。

Java强烈推荐在复制大量数组元素时用该方法,以取得更高的效率。

    4、注意ArrayList的两个转化为静态数组的toArray方法。

    第一个,Object[] toArray()方法。

该方法有可能会抛出java.lang.ClassCastException异常。假设直接用向下转型的方法。将整个ArrayList集合转变为指定类型的Array数组,便会抛出该异常,而假设转化为Array数组时不向下转型。而是将每个元素向下转型,则不会抛出该异常。显然对数组中的元素一个个进行向下转型,效率不高,且不太方便。

    第二个,<T> T[] toArray(T[] a)方法。该方法能够直接将ArrayList转换得到的Array进行总体向下转型(转型事实上是在该方法的源代码中实现的),且从该方法的源代码中能够看出,參数a的大小不足时,内部会调用Arrays.copyOf方法。该方法内部创建一个新的数组返回,因此对该方法的经常使用形式例如以下:

public static Integer[] vectorToArray2(ArrayList<Integer> v) {
Integer[] newText = (Integer[])v.toArray(new Integer[0]);
return newText;
}

     5、ArrayList基于数组实现,能够通过下标索引直接查找到指定位置的元素,因此查找效率高。但每次插入或删除元素,就要大量地移动元素,插入删除元素的效率低。

    6、在查找给定元素索引值等的方法中,源代码都将该元素的值分为null和不为null两种情况处理,ArrayList中同意元素为null。
  

   

本篇博文參加了CSDN博文大赛。假设您认为这篇博文不错。希望您能帮我投一票,谢谢!

投票地址:http://vote.blog.csdn.net/Article/Details?articleid=35568011

【Java集合源代码剖析】ArrayList源代码剖析的更多相关文章

  1. 【转】Java集合:HashMap源码剖析

    Java集合:HashMap源码剖析   一.HashMap概述二.HashMap的数据结构三.HashMap源码分析     1.关键属性     2.构造方法     3.存储数据     4.调 ...

  2. Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  3. java集合系列之ArrayList源码分析

    java集合系列之ArrayList源码分析(基于jdk1.8) ArrayList简介 ArrayList时List接口的一个非常重要的实现子类,它的底层是通过动态数组实现的,因此它具备查询速度快, ...

  4. Java集合框架之ArrayList浅析

    Java集合框架之ArrayList浅析 一.ArrayList综述: 位于java.util包下的ArrayList是java集合框架的重要成员,它就是传说中的动态数组,用MSDN中的说法,就是Ar ...

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

    最近忙着替公司招人好久没写了,荒废了不好意思. 上一章学习了Collection的架构,并阅读了部分源码,这一章开始,我们将对Collection的具体实现进行详细学习.首先学习List.而Array ...

  6. 【Java集合系列】---ArrayList

    开篇前言--ArrayList中的基本方法 前面的博文中,小编主要简单介绍java集合的总体架构,在接下来的博文中,小编将详细介绍里面的各个类,通过demo.对比,来对java集合类进行更加深入的理解 ...

  7. java集合系列之三(ArrayList)

    上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解ArrayLi ...

  8. java集合之深入分析ArrayList

    ArrayList特点: ArrayList方法实现: 扩容方法的实现: 源码: private void ensureCapacityInternal(int minCapacity) { //如果 ...

  9. Java——集合框架之ArrayList,LinkedList,迭代器Iterator

    概述--集合框架 Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(具体实现接口的类).所有抽象出来的数据结构和操作(算法)统称为Java集合框架(Java Collection ...

  10. Java集合框架(一)-ArrayList

    大佬理解->Java集合之ArrayList 1.ArrayList的特点 存放的元素有序 元素不唯一(可以重复) 随机访问快 插入删除元素慢 非线程安全 2.底层实现 底层初始化,使用一个Ob ...

随机推荐

  1. MVC登录前准备写好cookie

    Insus.NET写过一系列的MVC的练习,昨天学习了jQuery的验证<在MVC应用程序中使用jQuery的验证>http://www.cnblogs.com/insus/p/34626 ...

  2. AngularJS学习笔记(五)自定义指令(1)

    先来说说自定义指令 ng通过内置指令的方式实现了对html的增强,同时也赋予了我们自定义指令的功能,让我们根据实际需求进行指令的定制.自定义指令涉及到模板(template).作用域(scope).数 ...

  3. Commonjs、AMD、CMD

    CommonJS 该规范的核心思想是允许模块通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或 module.exports 来导出需要暴露的接口 require(& ...

  4. ELK环境搭建完整说明

    ELK环境搭建完整说明 ELK:ElasticSerach.Logstash.Kibana三款产品名称的首字母集合,用于日志的搜集和搜索.简单地理解为我们可以把服务端的日志(nginx.tomcat等 ...

  5. thinkphp 分页Pages

    位置: Thinkphp/Library/Think/Pages 或Page pages.class.php <?php // +-------------------------------- ...

  6. SQL Server无法打开物理文件,操作系统错误 5:"5(拒绝访问。)的解决办法

    在新装的系统中使用SQL Server附加以前的数据库的时候可能会遇到“无法打开物理文件,拒绝访问”的错误,如下图: 解决方法为使用windows验证登录,或者更改SQL Server内置账户类型为L ...

  7. SVN问题之——org.apache.subversion.javahl.ClientException: Attempted to lock an already-locked dir(网摘文)

    一.问题描述 今天在 Eclipse 中用 SVN 插件提交代码时遇到 org.apache.subversion.javahl.ClientException: Attempted to lock ...

  8. 【Java基础】8、java中的native方法

    native是与C++联合开发的时候用的!java自己开发不用的! 使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用.这些函 ...

  9. Cookies读写

    /** * Minified by jsDelivr using Terser v3.14.1. * Original file: /npm/js-cookie@2.2.0/src/js.cookie ...

  10. 2.Observer Pattern(观察者模式)

    Observer Pattern(观察者模式)定义: 在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新. 干说定义肯定没有举例理解的透彻.想到Observ ...