`

java ArrayList源码 上

阅读更多

   版本 jdk-7u71-windows-x64

 

          JavaSE7 ArrayList源码下:http://flyouwith.iteye.com/blog/2171047 

/**
 * 看下面这几个私有属性,就知道ArrayList实际上就是一个数组
 * 其(数组、ArrayList)数据结构就是一个简单的线性序列
 */
public class ArrayList<E> 
		extends AbstractList<E> //这个  extends AbstractCollection<E> implements List<E>
		implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
	private static final long serialVersionUID = 8683452581122892189L;

	/**
	 * 默认初始容量.
	 */
	private static final int DEFAULT_CAPACITY = 10;

	/**
	 * 空数组
	 */
	private static final Object[] EMPTY_ELEMENTDATA = {};

	/**
	 * 数组elementData 存储ArrayList的所有数据
	 */
	private transient Object[] elementData;

	/**
	 * size<=elementData.length,两者没什么特别关系 
	 * size是数组elementData中元素(E) 的个数 
	 */
	private int size;

	/**
	 * 构造方法1
	 * 构造一个与指定初始容量的空列表.
	 * 例:ArrayList<E> array = new ArrayList<E>(10000); 
	 * 这时候size=0,但是数组的容量是10000  
	 */
	public ArrayList(int initialCapacity) {
		super();
		if (initialCapacity < 0)
			throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
		this.elementData = new Object[initialCapacity];
	}

	/**
	 * 构造方法2
	 * api:构造一个空列表的初始容量10
	 * 我就不明白了,那里初始化容量大小了?、????
	 * 明明是构造一个容量是0的数组
	 */
	public ArrayList() {
		super();
		this.elementData = EMPTY_ELEMENTDATA;
	}

	/**
	 * 构造方法3
	 * 可以放一个实现Collection接口的集合进去set、list
	 */
	public ArrayList(Collection<? extends E> c) {
		//  1.将集合转换成数组,elementData指向这个数组 
		elementData = c.toArray();
		//  2.设置size值     
		size = elementData.length;
	    //  3.判断ele..是不是Object数组,不是的话创建一个,将内容(基本类型的值,对象的引用)copy进新数组中,返回   
		if (elementData.getClass() != Object[].class)
			elementData = Arrays.copyOf(elementData, size, Object[].class);
	}

    

 

 下面看一下,构造方法3的第一步(假设传进来的是一个ArrayList)和第三步。

/**
	 * ArrayList实现的 Collection接口中toArray()方法
	 */
		public Object[] toArray() {
			return Arrays.copyOf(elementData, size);
		}
	  /**
	   * 在Arrays类中找到的copyOf的方法
	   */
	    public static <T> T[] copyOf(T[] original, int newLength) {
	        return (T[]) copyOf(original, newLength, original.getClass());
	    }
	  /**
	   * 直接看这个吧,上面构造方法3的第三步调用的也是这个方法
	   */
	    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
			 //根据给定的paramClass数组类型,生成一个大小newLength的新数组
	        T[] copy = 
    		        //三目运算
	        		((Object)newType == (Object)Object[].class)
	        		//构造方法3的第三步走的这里
		            ? (T[]) new Object[newLength]
		            //Array.newInstance 是native的,看不到了		
		            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
	          //这个也是	native方法,x = Math.min(original.length, newLength)
	          //复制original[0~x]内容到copy[0~x]中,用这个操作数组还是很爽的	
	        System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));
	        return copy;
	    }
	

  

 

  其实一般的构造方法3,第三步都会走。

ArrayList<String> array = new ArrayList<String>(Arrays.asList("a","b"));
		//对应构造方法3的第一步
		Object[] elementData = Arrays.asList("a","b").toArray();
		System.err.println(elementData.getClass());//输出class [Ljava.lang.String;

  

下面继续源码:对数组进行扩容

	/**
	 * 给数组瘦身,释放资源,确定数组大小不会改变时用这个.
	 * 生成一个新数组容量与元素个数一样  
	 */
	public void trimToSize() {
		//记录对arrayList的操作次数? 源码下再介绍
		modCount++;
		if (size < elementData.length) {
			//上面介绍过了   
			elementData = Arrays.copyOf(elementData, size);
		}
	}

	/**
	 * 手动给数组扩容,生成一个容量不小于paramInt数组,然后将内容copy进去  
	 */
	public void ensureCapacity(int minCapacity) {
		int minExpand = (elementData != EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY;
		if (minCapacity > minExpand) {
			ensureExplicitCapacity(minCapacity);
		}
	}

	private void ensureCapacityInternal(int minCapacity) {
		if (elementData == EMPTY_ELEMENTDATA) {
			minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
		}
		ensureExplicitCapacity(minCapacity);
	}

	private void ensureExplicitCapacity(int minCapacity) {
		modCount++;
		if (minCapacity - elementData.length > 0)
			// 给定数值不能比当前数组容量小: 执行
			grow(minCapacity);
	}

	/**
	 * 数组分配的最大大小,超过的话取Integer.MAX_VALUE
	 */
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

	/**
	 * 执行扩容  
	 */
	private void grow(int minCapacity) {
		int oldCapacity = elementData.length;
		//自己会根据当前容量算出一个扩容值,跟给定值比较选择最大的   
		//移位操作符>> 参考:http://flyouwith.iteye.com/blog/2163032
		int newCapacity = oldCapacity + (oldCapacity >> 1);
		if (newCapacity - minCapacity < 0)
			newCapacity = minCapacity;
		//限定数组最大的容量
		if (newCapacity - MAX_ARRAY_SIZE > 0)
			newCapacity = hugeCapacity(minCapacity);
		//继续copy  到一个新数组中
		elementData = Arrays.copyOf(elementData, newCapacity);
	}

	/**
	 * 限定数组最大容量不能超过Integer.MAX_VALUE=2147483647
	 */
	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 int size() {
		return size;
	}

	/**
	 * 是否只有一副皮囊 .
	 */
	public boolean isEmpty() {
		return size == 0;
	}

	/**
	 * 是否包含指定o
	 */
	public boolean contains(Object o) {
		return indexOf(o) >= 0;
	}

	/**
	 *  返回在数组中第一次出现的位置,没有找到返回-1
	 *  通过对象的equals比较
	 */
	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;
	}

	/**
	 *  返回在数组中最后一次出现的位置,没有找到返回-1
	 *  从后面开始循环
	 *  通过对象的equals比较
	 */
	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实例。(元素
     * 本身并不是复制。)
	 * 数组存基本类型的值,对象的引用。  
     * 所以copy的不过是引用,都指向一个对
	 */
	public Object clone() {
		try {
			@SuppressWarnings("unchecked")
			ArrayList<E> v = (ArrayList<E>) super.clone();
			v.elementData = Arrays.copyOf(elementData, size);
			v.modCount = 0;
			return v;
		} catch (CloneNotSupportedException e) {
			throw new InternalError();
		}
	}

	/**
	 * 返回一个数组,其中包含所有的元素在这个列表中
     * 顺序(从第一个到最后一个元素)。
	 * 对象copy引用
	 * 该方法基于数组的和基于集合的api之间充当桥梁。
	 */
	public Object[] toArray() {
		return Arrays.copyOf(elementData, size);
	}

	/**
	 * 新建一个数组,放到这里拷贝ArrayList中内容  
	 */
	@SuppressWarnings("unchecked")
	public <T> T[] toArray(T[] a) {
		//如果给定数组容量小于size ,则生成一个大小是size的数组,然后把内容copy进去
		if (a.length < size)
			return (T[]) Arrays.copyOf(elementData, size, a.getClass());
		//否则直接copy,上面有介绍这个方法的含义 
		System.arraycopy(elementData, 0, a, 0, size);
		if (a.length > size)
			a[size] = null;
		return a;
	}

	// 返回数组指定位置的元素

	@SuppressWarnings("unchecked")
	E elementData(int index) {
		return (E) elementData[index];
	}

	/**
	 * 返回在该列表中指定位置的元素
	 */
	public E get(int index) {
		rangeCheck(index);//检核是否越界 

		return elementData(index);
	}

	/**
	 *替换指定位置的元素,返回被替换元素  
	 */
	public E set(int index, E element) {
		rangeCheck(index);//检核是否越界 
		E oldValue = elementData(index);
		elementData[index] = element;
		return oldValue;
	}

	/**
	 * 在末尾添加元素。.
	 * 第一步上面有介绍这个方法。是否需要扩容
	 * 注意:size加1
	 */
	public boolean add(E e) {
		ensureCapacityInternal(size + 1); 
		elementData[size++] = e;
		return true;
	}

	/**
	 * 指定位置添加元素,从指定位置开始后面元素统一后移一位  .
	 * 这里不是用的for循环来移位,而是copy,即使这样也比LinkedList慢好多 
	 * 这个如果用for循环的话时间复杂度是O(this.size - index) copy应该是比这小的 
	 * 但是肯定比LinkedList 的O(1) 要大的多
	 * 注意:size加1  
	 */
	public void add(int index, E element) {
		rangeCheckForAdd(index);
		ensureCapacityInternal(size + 1);//检核是否越界
		System.arraycopy(elementData, index, elementData, index + 1, size - index);
		elementData[index] = element;
		size++;
	}

	/**
	 *  跟上面性质是一样的。把删除位置后面的元素统一向前移动一位
	 *  比LinkedList慢  
	 *  注意:size减1
	 */
	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);
		//然后把最后一个元素删掉
		elementData[--size] = null; 

		return oldValue;
	}

	/**
	 * 删除第一次出现的指定元素从这个列表
	 * 通过for循环查找元素
	 */
	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; 
	}

	/**
	 * 清空,通过for循环
	 */
	public void clear() {
		modCount++;

		for (int i = 0; i < size; i++)
			elementData[i] = null;

		size = 0;
	}

	/**
	 * 添加一个集合到当前集合后面 
	 * 先把要添加的集合转变成数组,然后对this数组扩容,copy到this数组中
	 * 比LinkedList慢
	 */
	public boolean addAll(Collection<? extends E> c) {
		Object[] a = c.toArray();
		int numNew = a.length;
		ensureCapacityInternal(size + numNew); // 扩容
		System.arraycopy(a, 0, elementData, size, numNew);
		size += numNew;
		return numNew != 0;
	}

	/**
	 * 在指定位置插入集合.
	 * 先进行扩容,然后移位,之后把内容copy进来 
	 */
	public boolean addAll(int index, Collection<? extends E> c) {
		rangeCheckForAdd(index);

		Object[] a = c.toArray();
		int numNew = a.length;
		ensureCapacityInternal(size + numNew);  // 扩容

		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;
	}

	/**
	 * 这是protected的不能用。。  
	 * remove区间的内容
	 * 先把fromIndex后的内容copy到toIndex后面  
	 * 然后把后面toIndex-fromIndex个数的元素清空
	 */
	protected void removeRange(int fromIndex, int toIndex) {
		modCount++;
		int numMoved = size - toIndex;
		System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);

		int newSize = size - (toIndex - fromIndex);
		for (int i = newSize; i < size; i++) {
			elementData[i] = null;
		}
		size = newSize;
	}

	/**
	 *  检核越界
	 */
	private void rangeCheck(int index) {
		if (index >= size)
			throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	}

	/**
	 * 检核越界 
	 */
	private void rangeCheckForAdd(int index) {
		if (index > size || index < 0)
			throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	}

	/**
	 * 异常信息 .
	 */
	private String outOfBoundsMsg(int index) {
		return "Index: " + index + ", Size: " + size;
	}

 

  

 

1
1
分享到:
评论

相关推荐

    ArrayList源码分析

    ArrayList是Java集合框架中的一员,它是List接口的一个实现,提供了动态数组的功能。ArrayList的主要特点是它在内存中以数组的形式存储元素,因此对于随机访问元素,它的性能非常高效。本篇文章将深入探讨ArrayList...

    ArrayList源码分析(含jdk1.8).pdf

    通过以上对ArrayList源码的分析,可以总结出如下关键知识点: 1. ArrayList的实现基于动态数组,可以动态地进行容量的调整; 2. ArrayList具有默认初始化容量10,以及无参构造时延迟初始化的特性; 3. ArrayList...

    ArrayList源码.zip

    ArrayList是Java编程语言中最常用的集合...总之,这个“ArrayList源码.zip”文件是Java程序员学习和优化代码的宝贵资源,它揭示了ArrayList内部的工作机制,帮助我们提升编程技巧,更好地理解和利用这个强大的集合类。

    Java中ArrayList类的源码解析

    Java中ArrayList类的源码解析 ArrayList是Java中最常用的集合类之一,它实现了List接口,继承自AbstractList抽象类。在ArrayList中,我们可以看到它的源码实现了Iterable接口、List接口和Collection接口。下面我们...

    ArrayList源码Jdk1.8

    ### ArrayList源码解析(JDK 1.8) #### 概述 `ArrayList`是Java集合框架中的一个核心组件,它提供了动态数组的功能。与固定大小的数组不同,`ArrayList`可以随着元素的增加而自动扩展其容量。在JDK 1.8中,`...

    JDK8的ArrayList源码文件

    JDK8的ArrayList源码文件

    Java源码大全

    综上所述,Java源码大全是一个全面的Java学习资源,无论你是初学者还是有经验的开发者,都能从中找到有价值的代码示例和学习素材。通过这个压缩包,你可以系统地学习Java语言,掌握各种编程技巧,以及提升算法设计和...

    查看Java类库源码

    2. **验证源码可见性**:返回IDE的项目视图,尝试打开某个Java类,如`String`或`ArrayList`。如果一切设置正确,IDE应能成功加载并显示对应类的源代码。 #### 扩展知识点 - **JRE与JDK的区别**:JRE(Java Runtime...

    ArrayList扩容机制源码解析.md

    本资源根据个人学习和总结,主要介绍Java中ArrayList扩容机制源码的解析,主要包含文字和代码等内容,以源码的形式进行分析,详细介绍了ArrayList扩容机制的整个流程,特此将该资源分享

    java源码文档src

    `java.util`包下的`List`、`Set`、`Map`等接口以及它们的实现类,如`ArrayList`、`HashMap`等,构成了Java集合框架。源码解析可以帮助我们理解这些数据结构的内部实现,优化数据存储和操作。 8. **网络编程** `...

    Thinking in Java 4 源码 导入IDEA可直接运行

    其次,集合框架部分的源码将展示ArrayList、LinkedList、HashSet、HashMap等各种容器的使用方法,以及泛型、迭代器和比较器的概念。这部分代码可以帮助你理解Java集合的强大功能和灵活性。 再者,多线程编程的源码...

    Java SE 源码 Java SE 源码

    7. **集合框架**:Java集合框架包括数组、列表、队列、映射等数据结构,如`ArrayList`、`HashMap`等。源码揭示了这些数据结构的实现细节,对于优化和定制自己的数据结构非常有用。 8. **IO/NIO**:`java.io`和`java...

    Java 编程 源码 处理

    4. **集合框架**:Java集合框架包括List、Set、Map等接口及其实现类,如ArrayList、HashSet、HashMap等。源码分析能帮助理解它们的工作机制和性能特点,选择合适的数据结构存储和操作数据。 5. **多线程编程**:...

    Java编程中ArrayList源码分析

    Java编程中ArrayList源码分析 Java编程中ArrayList源码分析是Java编程中一个重要的知识点,对于Java开发者来说,了解ArrayList的源码可以帮助他们更好地理解Java集合框架的实现机制,从而提高自己的编程水平。 ...

    Java集合框架ArrayList源码分析(一)

    《深入剖析Java集合框架ArrayList源码》 Java集合框架中的ArrayList是开发者常用的数据结构,它是一种基于动态数组实现的列表。ArrayList的特点在于它的内部结构、性能优化以及在并发环境下的处理方式。本文将深入...

    Java大全源码包

    4. **集合框架**:Java集合框架是用于存储和操作对象的工具,包括List(如ArrayList、LinkedList)、Set(如HashSet、TreeSet)和Map(如HashMap、TreeMap)。源码可能包含各种数据结构的实现和操作,比如查找、排序...

    Java 集合框架(2-9)-Collection - ArrayList 源码解析.pdf

    《Java集合框架(2-9)-Collection - ArrayList 源码解析》 ArrayList是Java集合框架中的一个重要组件,它属于List接口的实现类,提供了一种动态数组的逻辑视图。ArrayList以高效、灵活的方式存储和操作对象序列,是...

    第二章 ArrayList源码解析1

    第二章 ArrayList源码解析 ArrayList是Java集合框架中的一种动态数组,它继承自AbstractList,并实现了List接口。ArrayList主要用于存储可变大小的对象列表,它的核心是通过一个Object类型的数组elementData来实现...

    java贪吃蛇源码

    此外,还会使用到Java集合框架中的数组和ArrayList来存储游戏元素。 2. **图形用户界面(GUI)**:游戏的界面通常是使用Java的Swing或JavaFX库来创建的。Swing提供了诸如JFrame、JPanel、JButton等组件,用于构建...

Global site tag (gtag.js) - Google Analytics