自己动手写写:ArrayList源码浅析

http://boy00fly.iteye.com/blog/1138417


了解你所使用的东西,最直接有效的方式莫过于源码切入的方式!

 

最近会写一个源码分析的系列文章!这篇文章先从最常用的例子ArrayList下手剖析!

 

一. ArrayList

 

下面是ArrayList的类结构

Java代码   收藏代码
  1. public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable  

 

1. 两个重要的成员变量

 

Java代码   收藏代码
  1. /** 
  2.  * The array buffer into which the elements of the ArrayList are stored. 
  3.  * The capacity of the ArrayList is the length of this array buffer. 
  4.  */  
  5. private transient Object[] elementData;  
  6.   
  7. /** 
  8.  * The size of the ArrayList (the number of elements it contains). 
  9.  * 
  10.  * @serial 
  11.  */  
  12. private int size;  

我们知道ArrayList的内部真实的存储结构是数组,正是此elmentDate; size很明显就是ArrayList的长度(这可不是数组的长度)。

 

2. 三个构造函数

 

Java代码   收藏代码
  1. /** 
  2.  * Constructs an empty list with the specified initial capacity. 
  3.  * 
  4.  * @param   initialCapacity   the initial capacity of the list 
  5.  * @exception IllegalArgumentException if the specified initial capacity 
  6.  *            is negative 
  7.  */  
  8. public ArrayList(int initialCapacity)  
  9. {  
  10.     super();  
  11.     if (initialCapacity < 0)  
  12.         throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);  
  13.     this.elementData = new Object[initialCapacity];  
  14. }  

   initialCapacity是初始化数组长度的参数。

 

 

Java代码   收藏代码
  1. /** 
  2.  * Constructs an empty list with an initial capacity of ten. 
  3.  */  
  4. public ArrayList()  
  5. {  
  6.     this(10);  
  7. }  

 默认初始化数组的长度为10

 

 

Java代码   收藏代码
  1. /** 
  2.  * Constructs a list containing the elements of the specified 
  3.  * collection, in the order they are returned by the collection's 
  4.  * iterator. 
  5.  * 
  6.  * @param c the collection whose elements are to be placed into this list 
  7.  * @throws NullPointerException if the specified collection is null 
  8.  */  
  9. public ArrayList(Collection<? extends E> c)  
  10. {  
  11.     elementData = c.toArray();  
  12.     size = elementData.length;  
  13.     // c.toArray might (incorrectly) not return Object[] (see 6260652)  
  14.     if (elementData.getClass() != Object[].class)  
  15.         elementData = Arrays.copyOf(elementData, size, Object[].class);  
  16. }  

 上面这个构造函数也没啥好说的,使用另外一个Collection初始化,就是将数据c的内容copy到elementData中。

 

3. 几个重要的方法

 

Java代码   收藏代码
  1. /** 
  2.  * Inserts the specified element at the specified position in this 
  3.  * list. Shifts the element currently at that position (if any) and 
  4.  * any subsequent elements to the right (adds one to their indices). 
  5.  * 
  6.  * @param index index at which the specified element is to be inserted 
  7.  * @param element element to be inserted 
  8.  * @throws IndexOutOfBoundsException {@inheritDoc} 
  9.  */  
  10. public void add(int index, E element)  
  11. {  
  12.     if (index > size || index < 0)  
  13.         throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);  
  14.       
  15.     ensureCapacity(size + 1); // Increments modCount!!  
  16.     System.arraycopy(elementData, index, elementData, index + 1, size - index);  
  17.     elementData[index] = element;  
  18.     size++;  
  19. }  

这个add方法的作用就是将此element插入到数组下表为index下,如果超出当前size会报错的。

其中ensureCapacity(size + 1); 的作用是什么呢?我们来看一下这个方法的内容!

 

Java代码   收藏代码
  1. /** 
  2.  * Increases the capacity of this <tt>ArrayList</tt> instance, if 
  3.  * necessary, to ensure that it can hold at least the number of elements 
  4.  * specified by the minimum capacity argument. 
  5.  * 
  6.  * @param   minCapacity   the desired minimum capacity 
  7.  */  
  8. public void ensureCapacity(int minCapacity)  
  9. {  
  10.     modCount++;  
  11.     int oldCapacity = elementData.length;  
  12.     if (minCapacity > oldCapacity)  
  13.     {  
  14.         Object oldData[] = elementData;  
  15.         int newCapacity = (oldCapacity * 3) / 2 + 1;  
  16.         if (newCapacity < minCapacity)  
  17.             newCapacity = minCapacity;  
  18.         // minCapacity is usually close to size, so this is a win:  
  19.         elementData = Arrays.copyOf(elementData, newCapacity);  
  20.     }  
  21. }  

 没错,这个方法就是扩充elementData数组的长度所用。新增一条数据后,如果发现当前elementData数组的长度不够时,会扩充elementData数组,扩充后的elementData数组的长度是原elementData的长度*3/2 + 1后的长度。ps:为啥扩充了一半左右,还不清楚。

 

 看得出来,ArrayList的内存就是维护了一个数组,通过不断的新建长度更长的数组并复制数据来完成的!这也就决定了ArrayList的插入速度在需要扩容的时候会比较慢,但是索引查询的数组是相当的快!ps:扩建数组的代价相对而言还是较大的,对于能够预估容量的情况下可以直接初始化一定容量的数组。

 

Java代码   收藏代码
  1. /** 
  2.  * Returns the element at the specified position in this list. 
  3.  * 
  4.  * @param  index index of the element to return 
  5.  * @return the element at the specified position in this list 
  6.  * @throws IndexOutOfBoundsException {@inheritDoc} 
  7.  */  
  8. public E get(int index)  
  9. {  
  10.     RangeCheck(index);  
  11.       
  12.     return (E)elementData[index];  
  13. }  

   根据索引获得对象,没啥好说的!其中RangeCheck(index)是检查下表是否越界!

 

Java代码   收藏代码
  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.  * 
  6.  * @param index the index of the element to be removed 
  7.  * @return the element that was removed from the list 
  8.  * @throws IndexOutOfBoundsException {@inheritDoc} 
  9.  */  
  10. public E remove(int index)  
  11. {  
  12.     RangeCheck(index);  
  13.       
  14.     modCount++;  
  15.     E oldValue = (E)elementData[index];  
  16.       
  17.     int numMoved = size - index - 1;  
  18.     if (numMoved > 0)  
  19.         System.arraycopy(elementData, index + 1, elementData, index, numMoved);  
  20.     elementData[--size] = null// Let gc do its work  
  21.       
  22.     return oldValue;  
  23. }  

 根据索引移除对象的方法。就是将index后面的所有对象向前移动一位,并将elementData[--size] = null; // Let gc do its work

其中modCount参数是父类AbstractList中定义的,详情如下:

 

Java代码   收藏代码
  1. /**                                                                        
  2.  * The number of times this list has been <i>structurally modified</i>.    
  3.  * Structural modifications are those that change the size of the          
  4.  * list, or otherwise perturb it in such a fashion that iterations in      
  5.  * progress may yield incorrect results.                                   
  6.  *                                                                         
  7.  * <p>This field is used by the iterator and list iterator implementation  
  8.  * returned by the {@code iterator} and {@code listIterator} methods.      
  9.  * If the value of this field changes unexpectedly, the iterator (or list  
  10.  * iterator) will throw a {@code ConcurrentModificationException} in       
  11.  * response to the {@code next}, {@code remove}, {@code previous},         
  12.  * {@code set} or {@code add} operations.  This provides                   
  13.  * <i>fail-fast</i> behavior, rather than non-deterministic behavior in    
  14.  * the face of concurrent modification during iteration.                   
  15.  *                                                                         
  16.  * <p><b>Use of this field by subclasses is optional.</b> If a subclass    
  17.  * wishes to provide fail-fast iterators (and list iterators), then it     
  18.  * merely has to increment this field in its {@code add(int, E)} and       
  19.  * {@code remove(int)} methods (and any other methods that it overrides    
  20.  * that result in structural modifications to the list).  A single call to 
  21.  * {@code add(int, E)} or {@code remove(int)} must add no more than        
  22.  * one to this field, or the iterators (and list iterators) will throw     
  23.  * bogus {@code ConcurrentModificationExceptions}.  If an implementation   
  24.  * does not wish to provide fail-fast iterators, this field may be         
  25.  * ignored.                                                                
  26.  */                                                                         
  27. protected transient int modCount = 0;                                       

 这里注释也说明的很清楚了,modCount的含义就modify count(list的修改次数),这是一个可选的参数,子类完全可以不操作这个成员变量,但是如果你想提供一个 fail-fast iterators,你就需要在每次修改时modCount++。

 

 

Java代码   收藏代码
  1. /** 
  2.  * Returns the index of the first occurrence of the specified element 
  3.  * in this list, or -1 if this list does not contain the element. 
  4.  * More formally, returns the lowest index <tt>i</tt> such that 
  5.  * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>, 
  6.  * or -1 if there is no such index. 
  7.  */  
  8. public int indexOf(Object o)  
  9. {  
  10.     if (o == null)  
  11.     {  
  12.         for (int i = 0; i < size; i++)  
  13.             if (elementData[i] == null)  
  14.                 return i;  
  15.     }  
  16.     else  
  17.     {  
  18.         for (int i = 0; i < size; i++)  
  19.             if (o.equals(elementData[i]))  
  20.                 return i;  
  21.     }  
  22.     return -1;  
  23. }  

查找容器内是否包含o对象并返回第一次找到的索引。这个也没啥好的办法呀,直接遍历一遍呗! 

 

Java代码   收藏代码
  1. /** 
  2.     * Returns an array containing all of the elements in this list 
  3.     * in proper sequence (from first to last element). 
  4.     * 
  5.     * <p>The returned array will be "safe" in that no references to it are 
  6.     * maintained by this list.  (In other words, this method must allocate 
  7.     * a new array).  The caller is thus free to modify the returned array. 
  8.     * 
  9.     * <p>This method acts as bridge between array-based and collection-based 
  10.     * APIs. 
  11.     * 
  12.     * @return an array containing all of the elements in this list in 
  13.     *         proper sequence 
  14.     */  
  15.    public Object[] toArray()  
  16.    {  
  17.        return Arrays.copyOf(elementData, size);  
  18.    }  

 返回数组形式的数据,也没啥好的。

 

Java代码   收藏代码
  1. /** 
  2.      * Returns an array containing all of the elements in this list in proper 
  3.      * sequence (from first to last element); the runtime type of the returned 
  4.      * array is that of the specified array.  If the list fits in the 
  5.      * specified array, it is returned therein.  Otherwise, a new array is 
  6.      * allocated with the runtime type of the specified array and the size of 
  7.      * this list. 
  8.      * 
  9.      * <p>If the list fits in the specified array with room to spare 
  10.      * (i.e., the array has more elements than the list), the element in 
  11.      * the array immediately following the end of the collection is set to 
  12.      * <tt>null</tt>.  (This is useful in determining the length of the 
  13.      * list <i>only</i> if the caller knows that the list does not contain 
  14.      * any null elements.) 
  15.      * 
  16.      * @param a the array into which the elements of the list are to 
  17.      *          be stored, if it is big enough; otherwise, a new array of the 
  18.      *          same runtime type is allocated for this purpose. 
  19.      * @return an array containing the elements of the list 
  20.      * @throws ArrayStoreException if the runtime type of the specified array 
  21.      *         is not a supertype of the runtime type of every element in 
  22.      *         this list 
  23.      * @throws NullPointerException if the specified array is null 
  24.      */  
  25.     public <T> T[] toArray(T[] a)  
  26.     {  
  27.         if (a.length < size)  
  28.             // Make a new array of a's runtime type, but my contents:  
  29.             return (T[])Arrays.copyOf(elementData, size, a.getClass());  
  30.         System.arraycopy(elementData, 0, a, 0, size);  
  31.         if (a.length > size)  
  32.             a[size] = null;  
  33.         return a;  
  34.     }  

 这个方法也是返回数组形式的数据,如果a.length < size 则按照a的运行时类型新建一个的数组,并把elementData的数组全部copy进去返回此数组,否则将elementData的数组copy进数组里面,并且将其他索引处置null.

 

当然还有一些其他的方法,这里就不再分析了,看看都懂得!下个章节介绍LinkedList的内容!

 

ps:以上是基于1.6版本的类库源码分析!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值