java_集合体系之ArrayList详解、源码及示例——03

java_集合体系之ArrayList详解、源码及示例——03


一:ArrayList结构图


java_集合体系之ArrayList详解、源码及示例——03_第1张图片

简单说明:

1、上图中虚线且无依赖字样、说明是直接实现的接口

2、虚线但是有依赖字样、说明此类依赖与接口、但不是直接实现接口

3、实线是继承关系、类继承类、接口继承接口

二:ArrayList类简介:


1、ArrayList是内部是以动态数组的形式来存储数据的、知道数组的可能会疑惑:数组不是定长的吗?这里的动态数组不是意味着去改变原有内部生成的数组的长度、而是保留原有数组的引用、将其指向新生成的数组对象、这样会造成数组的长度可变的假象。

2、ArrayList具有数组所具有的特性、通过索引支持随机访问、所以通过随机访问ArrayList中的元素效率非常高、但是执行插入、删除时效率比较地下、具体原因后面有分析。

3、ArrayList实现了AbstractList抽象类、List接口、所以其更具有了AbstractList和List的功能、前面我们知道AbstractList内部已经实现了获取Iterator和ListIterator的方法、所以ArrayList只需关心对数组操作的方法的实现、

4、ArrayList实现了RandomAccess接口、此接口只有声明、没有方法体、表示ArrayList支持随机访问。

5、ArrayList实现了Cloneable接口、此接口只有声明、没有方法体、表示ArrayList支持克隆。

6、ArrayList实现了Serializable接口、此接口只有声明、没有方法体、表示ArrayList支持序列化、即可以将ArrayList以流的形式通过ObjectInputStream/ObjectOutputStream来写/读。


三:ArrayList API

// Collection中定义的API
boolean             add(E object)
boolean             addAll(Collection collection)
void                clear()
boolean             contains(Object object)
boolean             containsAll(Collection collection)
boolean             equals(Object object)
int                 hashCode()
boolean             isEmpty()
Iterator         iterator()
boolean             remove(Object object)
boolean             removeAll(Collection collection)
boolean             retainAll(Collection collection)
int                 size()
 T[]             toArray(T[] array)
Object[]            toArray()
// AbstractList中定义的API
void                add(int location, E object)
boolean             addAll(int location, Collection collection)
E                   get(int location)
int                 indexOf(Object object)
int                 lastIndexOf(Object object)
ListIterator     listIterator(int location)
ListIterator     listIterator()
E                   remove(int location)
E                   set(int location, E object)
List             subList(int start, int end)
// ArrayList新增的API
Object               clone()
void                 ensureCapacity(int minimumCapacity)
void                 trimToSize()
void                 removeRange(int fromIndex, int toIndex)

总结:相对与AbstractCollection而言、多实现了List中新增的通过索引操作元素的方法。


四:ArrayList源码分析


package com.chy.collection.core;

import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.RandomAccess;
public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable {
	
    private static final long serialVersionUID = 8683452581122892189L;

    /** 保存ArrayList中元素的数组*/
    private transient Object[] elementData;

    /** 保存ArrayList中元素的数组的容量、即数组的size*/
    private int size;

    /** 使用指定的大小创建ArrayList*/
    public ArrayList(int initialCapacity) {
    	super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
        this.elementData = new Object[initialCapacity];
    }

    /** 使用默认的大小创建ArrayList*/
    public ArrayList() {
    	this(10);
    }

    /**
     * 使用指定的Collection构造ArrayList、构造之后的ArrayList中包含Collection中的元素、
     * 这些元素的排序方式是按照ArrayList的Iterator返回他们时候的顺序排序的
     */
    public ArrayList(Collection 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 实例的容量调整为列表的当前大小
     */
    public void trimToSize() {
    	//此集合总共被修改的次数
		modCount++;
		int oldCapacity = elementData.length;
		if (size < oldCapacity) {
	            elementData = Arrays.copyOf(elementData, size);
		}
    }

    /**
     * 确保此ArrayList的最小容量能容纳下参数minCapacity指定的容量、
     * 1、minCapacity大于原来容量、则将原来的容量增加(oldCapacity * 3)/2 + 1;
     * 2、若minCapacity仍然大于增加后的容量、则使用minCapacity作为ArrayList容量
     * 3、若minCapacity不大于增加后的容量、则使用增加后的容量。
     */
    public void ensureCapacity(int minCapacity) {
		modCount++;
		int oldCapacity = elementData.length;
		if (minCapacity > oldCapacity) {
		    Object oldData[] = elementData;
		    int newCapacity = (oldCapacity * 3)/2 + 1;
	    	    if (newCapacity < minCapacity)
	    	    	newCapacity = minCapacity;
	            // minCapacity is usually close to size, so this is a win:
	            elementData = Arrays.copyOf(elementData, newCapacity);
		}
    }

    /** 返回此列表中的元素的个数*/
    public int size() {
    	return size;
    }

    /** 如果此列表中没有元素,则返回 true*/
    public boolean isEmpty() {
    	return size == 0;
    }

    /**  如果此列表中包含指定的元素,则返回 true。*/
    public boolean contains(Object o) {
    	return indexOf(o) >= 0;
    }

    /** 返回指定对象在ArrayList中存放的第一个位置索引、注意空值的处理和Object.equals(? extends Object o)的返回值、不存在的话返回-1*/
    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;
    }

    /** 返回指定对象在ArrayList中存放最后一个位置的索引、注意空值的处理和Object.equals(? extends Object o)的返回值、不存在的话返回-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;
    }

    /** 返回一个当前集合的浅clone对象*/
    public Object clone() {
		try {
		    ArrayList v = (ArrayList) 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();
		}
    }

    /** 将当前ArrayList转换成Object数组、注意操作使用此方法转换后的数组有可能抛异常*/
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    /** 
     * 将当前ArrayList转换成与传入的T类型相同的数组、当传入的a的length小于ArrayList的size的时候、方法内部会生成一个新的T[]返回
     *	如果传入的T[]的length大于ArrayList的size、则T[]从下标size开始到最后的元素都自动用null填充。 
     */
    public  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;
    }

    // Positional Access Operations

    /** 获取ArrayList中索引为index位置的元素*/
    public E get(int index) {
    	RangeCheck(index);

    	return (E) elementData[index];
    }

    /** 将ArrayList的索引为index处的元素使用指定的E元素替换、返回被替换的原来的元素值*/
    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) {
    	//确保ArrayList的容量能够添加新的的元素
		ensureCapacity(size + 1);  // Increments modCount!!
		elementData[size++] = e;
		return true;
    }

    /** 将指定元素添加到指定的索引处 、
     *	注意:
     *	1、如果指定的index大于Object[] 的size或者小于0、则抛IndexOutOfBoundException
     *	2、检测Object[]是否需要扩容
     *	3、 将从index开始到最后的元素后移一个位置、
     *	4、将新添加的元素添加到index去。
     */
    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++;
    }

    /** 与add类似、
     * 	1、将指定index处的元素删除、
	 *	2、将index之后的所有元素前一一个位置、最后一个
	 *	3、将最后一个元素设置为null、--size
	 *
	 *	返回被删除的元素。
	 */
    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;
    }

    /** 删除Object[]中指定的元素Object 类似与contains方法与remove的结合体、只不过这里使用的是fastRemove方法去移除指定元素、移除成功则返回true*/
    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 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
    }

    /** 清空ArrayList*/
    public void clear() {
		modCount++;
	
		// Let gc do its work
		for (int i = 0; i < size; i++)
		    elementData[i] = null;
		size = 0;
    }

    /** 将指定集合中的所有元素追加到ArrayList中(从最后开始追加)*/
    public boolean addAll(Collection 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;
    }

    /** 将指定集合中的所有元素插入到idnex开始的后面位置处、原有的元素往后排*/
    public boolean addAll(int index, Collection 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(不包括)之间的所有元素。
     *	1、将Object[] 从toIdnex开始之后的元素(包括toIndex处的元素)移到Object[]下标从fromIndex开始之后的位置
     *	2、若有Object[]尾部要有剩余的位置则用null填充 
     */
    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);
    }

    /** 将此ArrayList写入到ObjectOutputStream流中、先写ArrayList存放元素的Object[]长度、再将Object[]中的每个元素写入到ObjectOutputStream流中*/
    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


总结:从ArrayList源码可以看出、ArrayList内部是通过动态数组来存储数据、从中我们也可以很容易的找到ArrayList的几个特性:

1、有序:如果不指定元素存放位置、则元素将依次从Object数组的第一个位置开始放、如果指定插入位置、则会将元素插入指定位置、后面的所有元素都后移

2、可重复:从源码中没有看到对存放的元素的校验

3、随机访问效率高:可以直接通过索引定位到我们要找的元素

4、自动扩容:ensureCapacity(int minCapacity)方法中会确保数组的最小size、当不够时会将原来的容量扩增到:(oldCapacity * 3) / 2 + 1。

5、变动数组元素个数(即添加、删除数组元素)效率低、在增删的操作中我们常见的一个函数: System.arraycopy()、他是将删除、或者添加之后、原有的元素进行移位、这是需要较大代价的。

6、 ArrayList不是线程安全的、即当使用多线程操作ArrayList时会有可能出错、后面总结会有。

五:ArrayList示例


因为使用集合、我们最关心的就是使用不同集合的不同方法的效率问题、而在这些中、最能体现效率问题的关键点是对集合的遍历、所以对于示例、分为两部分:第一部分是关于集合的不同的遍历方法的耗时示例、第二部分是集合的API的使用示例。


1、遍历方法:

01)使用Iterator遍历ArrayList

                for(Iterator iter = list.iterator(); iter.hasNext(); ) {
			iter.next();
		}

02)使用ListIterator遍历ArrayList

                for(Iterator iter = list.listIterator(); iter.hasNext(); ) {
			iter.next();
		}

03)使用随机访问(即for(int i=0;i

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

04)使用增强for循环遍历ArrayList


             for(@SuppressWarnings("unused") int i : list);


05)示例

package com.chy.collection.example;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

public class EragodicArrayList {

	/**
	 * 测试不同遍历方式的效率
	 */
	public static void testObtainAllElements(){
		//初始化一个较大的ArrayList
		ArrayList list = new ArrayList();
		for(int i=0; i<2000000; i++){
			list.add(i);
		}
		//零:使用Iterator
		long start = startTime();
		for(Iterator iter = list.iterator(); iter.hasNext(); ) {
			iter.next();
		}
		endTime(start);		//result: 63ms
		
		//一:使用Iterator
		long start0 = startTime();
		for(Iterator iter = list.listIterator(); iter.hasNext(); ) {
			iter.next();
		}
		endTime(start0);		//result: 78ms
		
		//二:使用随机访问、通过索引
		long start1 = startTime();
		for (int i = 0; i < list.size(); i++){
			list.get(i);
		}
		endTime(start1);	//result: 16ms
		
		//三:使用增强for循环
		long start2 = startTime();
		for(@SuppressWarnings("unused") int i : list);
		endTime(start2);	//result:62ms
		
		//四:使用ListIterator
		long start3 = startTime();
		ListIterator li = list.listIterator(0);
		while(li.hasNext()){
			li.next();
		}
		endTime(start3);	//result: 63ms
		
	}
	private static void endTime(long start) {
		long end = startTime();
		System.out.println(end - start + " ms");
	}

	private static long startTime() {
		long start = System.currentTimeMillis();
		return start;
	}
	
	public static void main(String[] args) {
		testObtainAllElements();
	}
}

结果及说明:

63 ms
78 ms
15 ms
63 ms
62 ms

从上面可以看出:使用随机访问效率最高、其他的差不多。


2、API演示

package com.chy.collection.example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.ListIterator;

import com.chy.collection.bean.Student;

public class ArrayListTest {

	/**
	 * 测试ArrayList的添加元素方法、以及与size有关的方法
	 */
	public static void testArrayListSize(){
		//use default object array's size 10
		ArrayList list = new ArrayList();
		list.add("a");
		list.add(1, "b");
		
		// use specified size 4
		ArrayList list2  = new ArrayList(4);
		list2.add("c");
		list2.add("d");
		list2.add("e");
		list2.add("f");
		
		//use specified size 5
		ArrayList list3  = new ArrayList(5);
		list3.add("g");
		list3.add("h");
		list3.add("i");
		list3.add("j");
		list3.add("k");
		list.addAll(list2);//从list末尾开始追加
		System.out.println(list.size());// result: 6
		list.addAll(6, list3);//从list索引6开始添加
		System.out.println(list.size());// result: 11
		//see AbstractCollection.toString();
		System.out.println(list);	//result: [a, b, c, d, e, f, g, h, i, j, k]
		
		// 对于ArrayList的大小、我们可以使用三个方法来操作
		list.add(null);
		list.add(null);
		System.out.println(list.size());
		list.trimToSize();//将list的大小设置成与其包含的元素相同、null也算是list中的元素、并且可以重复出现
		System.out.println(list.size());
		list.ensureCapacity(1);//确保list的大小不小于传入的参数值。
		System.out.println(list.size());
		System.out.println(list.size());
		
	}
	
	/**
	 * 测试ArrayList的包含、删除方法
	 */
	public static void testArrayListContainsRemove(){
		
		//初始化包含学号从1到10的十个学生的ArrayList
		ArrayList list1 = new ArrayList();
		Student s1 = new Student(1,"chy1");
		Student s2 = new Student(2,"chy2");
		Student s3 = new Student(3,"chy3");
		Student s4 = new Student(4,"chy4");
		list1.add(s1);
		list1.add(s2);
		list1.add(s3);
		list1.add(s4);
		for (int i = 5; i < 11; i++) {
			list1.add(new Student(i, "chy" + i));
		}
		System.out.println(list1);
		
		//初始化包含学号从1到4的四个学生的ArrayList
		ArrayList list2 = new ArrayList();
		list2.add(s1);
		list2.add(s2);
		list2.add(s3);
		list2.add(s4);
		
		//查看list1中是否包含学号为1的学生( 这里要注意、ArrayList中存放的都是对象的引用、而非堆内存中的对象)
		System.out.println(list1.contains(s1));
		
		//查看list1中是否包含list2
		System.out.println(list1.containsAll(list2));
		
		//从新构造一个指向学号为1的student、查看list2是否包含、不包含就添加进去、在判断list1是否包含list2
		Student newS1 = new Student(1, "newchy1");
		System.out.println("list2 contains newS1 ? " + list2.contains(newS1));
		
		if(!list2.contains(newS1)){
			list2.add(newS1);
		}
		System.out.println("list2 members :" + list2.toString());
		System.out.println("list1 contains list2 ? " + list1.containsAll(list2));
		
		//删除list1中索引为0的学生
		System.out.println(list1.remove(0));
		//如果学号为1的学生存在则删除、不存在删除学号为2的学生
		if(!list1.remove(s1)){
			System.out.println(list1.remove(s2));
		}
		//删除list2中的学生
		list1.removeAll(list2);
		System.out.println(list1);
		
		//清空list1
		list1.clear();
		
		//求list1与list2中元素的交集
		list1.retainAll(list2);
		System.out.println(list1);
	}
	
	/**
	 * 测试ArrayList的获取元素方法、
	 */
	public static void testObtainArrayListElements(){
		//将字符串数组转化成ArrayList
		String[] strArray = {"a", "b" ,"c", "d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
		
		/*
		使用时会抛异常、是由于Arrays.asList(strArray)返回的是一个Object[]、不能强转成ArrayList类型
		ArrayList list2 = (ArrayList)Arrays.asList(strArray);
		System.out.println(list2);
		*/
		
		//一般情况下使用下面这种转换方式、他会自动的将数组转换之后的类型设置为runtime时的类型
		ArrayList list1 = new ArrayList(Arrays.asList(strArray));
		System.out.println(list1);
		
		//获取某个索引处的元素
		System.out.println("str " + list1.get(0) + " size: " + list1.size());
		
		//将最后一个元素设置成"a"、打印被替换的元素
		System.out.println("old element :" + list1.set(list1.size()-1, list1.get(0)) + " list elements: " + list1);
		System.out.println();
		
		//返回第一个、最后一个“a”、“w”、“z”的索引、不存在则返回-1、内部是根据ListIterator来返回索引的
		System.out.println("first index of a : " + list1.indexOf("a") + " last index of a :" + list1.lastIndexOf("a"));
		System.out.println("first index of w : " + list1.indexOf("w") + " last index of w :" + list1.lastIndexOf("w"));
		System.out.println("first index of z : " + list1.indexOf("z") + " last index of z :" + list1.lastIndexOf("z"));
	}
	
	

	/**
	 * 对ListIterator方法的测试
	 */
	public static void testListIterator(){
		String[] strArray = {"a", "b" ,"c", "d","e"};
		ArrayList list = new ArrayList(Arrays.asList(strArray));
		
		//倒序遍历list
		ListIterator li = list.listIterator(list.size());
		while(li.hasPrevious()){
			System.out.println(li.previous());
		}
		System.out.println("================================");
		
		//以获取idnex方式  、正序遍历list
		ListIterator li1 = list.listIterator(0);
		while(li1.hasNext()){
			//System.out.println(li1.nextIndex());		会造成死循环、具体可以看源码
			//System.out.println(li1.previousIndex());		同样会造成死循环、具体可以看源码
			String s = li1.next();
			
			if("d".equals(s)){
				li1.set("a");
			}
			
			if("e".equals(s)){
				li1.add("f");
			}
			
			if("b".equals(s)){
				li1.remove();
			}
		}
		System.out.println(list);
		
		//对于在遍历过程中想获取index、要注意死循环、和字节想要获取的方式、具体可以自己动手试试
		ListIterator li2 = list.listIterator();
		while(li2.hasNext()){
			li2.next();
			System.out.println(li2.nextIndex() + "========" + li2.previousIndex());
		}
		
	}
	
	/**
	 * 测试ArrayList转换成Array时注意事项、附Array转换成List
	 */
	public static void testArrayList2Array(){
		//关于Array转换成ArrayList上面已经有过介绍、现在再补充一点特殊情况
		int[] intArray = new int[10];
		for (int i = 0; i < intArray.length; i++) {
			intArray[i] = i;
		}
		
		//将上面的数组转化成ArrayList
		//ArrayList list = Arrays.asList(intArray); 这种写法编译就会报错、因为集合的定义中、只能存放对象(其实是对象的引用)、所以我们要使用包装类型Integer
		
		//要先将上面的数组转换成Integer类型数组、只能手动转、不能强制或者自动转换、若有的话望贴出来啊
		Integer[] integerArray = new Integer[intArray.length];
		for (int i = 0; i < intArray.length; i++) {
			integerArray[i] = intArray[i];
		}
		
		//ArrayList list = (ArrayList)Arrays.asList(integerArray);
		//System.out.println(list.get(0)); 会报错、原因上面有
		
		//通常使用下面的转换方式
		ArrayList normalList = new ArrayList(Arrays.asList(integerArray));
		System.out.println(normalList.get(0));
		
		//第一种
		/*
		 * 会报强制转换错误、
		//ArrayList转换成Array
		Integer[] itg = (Integer[])normalList.toArray();
		System.out.println(itg[0]);
		*/
		
		//第二种
		Integer[] ia = new Integer[normalList.size()];
		normalList.toArray(ia);
		System.out.println(ia[0]);
		
		//第三种、应该使用这种形式的定义、传入的参数的本质是供toArray内部调用其类型、对其size简单处理一下、如果size大于list的size、则后面的补null、如果小于、则使用新的数组替换传入的、并作为结果返回
		Integer[] ia2 = normalList.toArray(new Integer[11]);
		System.out.println(ia2[10]);
		
		
		
	}
	
	/**
	 * 测试fail-fast机制
	 */
	public static void testFailFast(){
		String[] s = {"a", "b", "c", "d", "e"};
		ArrayList strList = new ArrayList(Arrays.asList(s));
		Iterator it = strList.iterator();
		while(it.hasNext()){
			String str = it.next();
			System.out.println(str);
			//这里本来是多线程动了ArrayList中的元素造成的、现在仅仅是模拟一种情况、就是在迭代的过程中、另一个线程向ArrayList中添加一个元素造成的fail-fast
			//异常信息:java.util.ConcurrentModificationException
			if("d".equals(str)){
				strList.add(str);
			}
		}
	}
	
	public static void main(String[] args) {
//		testArrayListSize();
//		testArrayListContainsRemove();
//		testObtainArrayListElements();
//		testArrayList2Array();
//		testFailFast();
		testListIterator();
	}
}


总结:

对于ArrayList、在记住其特性、有序可重复、便与查找、不便于增删的同时最好是能知道为什么他会有这些特性、其实源码就是最好的说明书、平常所接触的东西都是别人在源码的基础上分析得出的结论、只有自己的才是最适合自己的、别人总结的再好、看过、受教了、但是还是希望自己能动手总结一份、再差也是自己总结的、慢慢改进、只有自己的东西才是最适合自己的!


更多内容:java_集合体系之总体目录——00


你可能感兴趣的:(java_集合体系之ArrayList详解、源码及示例——03)