Java源码解读——ArrayList(一)

为了提高自己的Java开发能力,我也向高手、牛人学习,去解读源码。自己底子差了点,不过看个源码还是没问题的。第一站ArrayList。

源码为Java 1.7的源码

ArrayList是一个实现可变长数组,继承AbstractList类,实现所有的List接口,还实现了RandomAccess、Cloneable、Serializable接口。ArrayList不进行同步,除此之外基本和Vector等同。

 

1、成员变量

 

Java代码   收藏代码
  1. private transient Object[] elementData;  

elementData用于保存数据的数组。

 

Java代码   收藏代码
  1. private int size;  

 size为ArrayList内的数据数量,但并不是elementData的长度。

 

2、构造方法

Java代码   收藏代码
  1. public ArrayList(int initialCapacity) {  
  2.     super();  
  3.     if (initialCapacity < 0)  
  4.         throw new IllegalArgumentException("Illegal Capacity: "+  
  5.                                            initialCapacity);  
  6.     this.elementData = new Object[initialCapacity];  
  7. }  
  8.   
  9. public ArrayList() {  
  10.     this(10);  
  11. }  
  12.   
  13. public ArrayList(Collection<? extends E> c) {  
  14.     elementData = c.toArray();  
  15.     size = elementData.length;  
  16.     if (elementData.getClass() != Object[].class)  
  17.         elementData = Arrays.copyOf(elementData, size, Object[].class);  
  18. }  

  第一个是根据指定长度建立List,第二个是根据默认长度建立List,第三个根据传入Collection子类实例创建List。通过第三个实例看到Collection子类都会实现toArray()方法,可以看出至少很多Collection子类依赖于数组来实现(还没看过其他的集合实现,这只是我的妄言而已)。

 

3、add方法

Java代码   收藏代码
  1. public boolean add(E e) {  
  2.     ensureCapacityInternal(size + 1);   
  3.     elementData[size++] = e;  
  4.     return true;  
  5. }  

 该方法在数组最后添加一个元素。ensureCapacityInternal方法提供了ArrayList的自增长实现,以确保elementData有足够的长度来容纳新进入的元素(后面介绍自增长的实现)。

 

Java代码   收藏代码
  1. public void add(int index, E element) {  
  2.     rangeCheckForAdd(index);  
  3.   
  4.     ensureCapacityInternal(size + 1);   
  5.     System.arraycopy(elementData, index, elementData, index + 1,  
  6.                      size - index);  
  7.     elementData[index] = element;  
  8.     size++;  
  9. }  

 该方法是在第i个位置插入一个元素。rangeCheckForAdd方法用于检查index是否越界,代码如下:

Java代码   收藏代码
  1. private void rangeCheckForAdd(int index) {  
  2.     if (index > size || index < 0)  
  3.         throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
  4. }  

System.arraycopy方法使用native修饰符(这个修饰符第一次看到,谷歌了下,大致是说这个修饰的方法是通过底层实现的),效率自然高。arraycopy如果对同一个数组进行操作时,会首先把从源部分拷贝到一个临时数组,在把临时数组的元素拷贝到目标位置。值得注意的是,如果数组内不是基本类型,System.arraycopy的拷贝过来的也只是个引用而已。

 

4、remove方法

Java代码   收藏代码
  1. public E remove(int index) {  
  2.     rangeCheck(index);  
  3.   
  4.     modCount++;  
  5.     E oldValue = elementData(index);  
  6.   
  7.     int numMoved = size - index - 1;  
  8.     if (numMoved > 0)  
  9.         System.arraycopy(elementData, index+1, elementData, index,  
  10.                          numMoved);  
  11.     elementData[--size] = null;  
  12.   
  13.     return oldValue;  
  14. }  

 删除指定位置的元素,并返回删除的元素。以前还真没注意过删除时候还返回删除的元素。rangeCheck方法用于检查越界,代码如下:

Java代码   收藏代码
  1. private void rangeCheck(int index) {  
  2.     if (index >= size)  
  3.         throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
  4. }  

  modCount用于记录ArrayList的结构性变化的次数,add()、remove()、addall()、removerange()及clear()方法都会让modCount增长。add()及addall()方法的对modCount的操作在ensureCapacityInternal中。

numMoved用于检查删除的元素是否是最后ArrayList的最后一个元素(不一定是数组elementData的最后一个)。如果不是最后一个,则用arraycopy移动数组,最后将数组size-1处赋值为空。

 

Java代码   收藏代码
  1. public boolean remove(Object o) {  
  2.     if (o == null) {  
  3.         for (int index = 0; index < size; index++)  
  4.             if (elementData[index] == null) {  
  5.                 fastRemove(index);  
  6.                 return true;  
  7.             }  
  8.     } else {  
  9.         for (int index = 0; index < size; index++)  
  10.             if (o.equals(elementData[index])) {  
  11.                 fastRemove(index);  
  12.                 return true;  
  13.             }  
  14.     }  
  15.     return false;  
  16. }  

 删除与Object o相同的第一个元素。这里fastRemove方法,从代码来看和remove(int index)类似。

Java代码   收藏代码
  1. private void fastRemove(int index) {  
  2.     modCount++;  
  3.     int numMoved = size - index - 1;  
  4.     if (numMoved > 0)  
  5.         System.arraycopy(elementData, index+1, elementData, index,  
  6.                          numMoved);  
  7.     elementData[--size] = null;  
  8. }  

 

5、addAll方法

Java代码   收藏代码
  1. //将Collection c内的数据插入ArrayList中  
  2. public boolean addAll(Collection<? extends E> c) {  
  3.      Object[] a = c.toArray();  
  4.      int numNew = a.length;  
  5.      ensureCapacityInternal(size + numNew);  // Increments modCount  
  6.      System.arraycopy(a, 0, elementData, size, numNew);  
  7.      size += numNew;  
  8.      return numNew != 0;  
  9.  }  
  10.   
  11.  //将Collection c中的数据插入到ArrayList的指定位置  
  12.  public boolean addAll(int index, Collection<? extends E> c) {  
  13.      rangeCheckForAdd(index);  
  14.   
  15.      Object[] a = c.toArray();  
  16.      int numNew = a.length;  
  17.      ensureCapacityInternal(size + numNew);  // Increments modCount  
  18.   
  19.      int numMoved = size - index;  
  20.      if (numMoved > 0)  
  21.          System.arraycopy(elementData, index, elementData, index + numNew,  
  22.                           numMoved);  
  23.   
  24.      System.arraycopy(a, 0, elementData, index, numNew);  
  25.      size += numNew;  
  26.      return numNew != 0;  
  27.  }  

这两个方法都会调用ensureCapacityInternal方法使数组能够容纳下新的数据。后一个方法会判断是否是在数据最后插入,如果是则和第一个方法相同,如果不是,则先使用arraycopy移动数组。

 

6、removeAll和retainAll

删除或保留ArrayList中包含Collection c中的的元素,这两个方法都依赖batchRemove(Collection<?> c, boolean complement)实现。

 

7、get和set

前者是获取元素,后者是替换某个位置上的元素,然后返回被替换的元素。这两个都用rangeCheck做越界检查。set方法不进行自增长,也就说替换的元素必须是size内的。

 

 

 

发现感觉快把源码复制过来了。唉,以后不能这么写.

 转自:http://iamxi.iteye.com/blog/1451921

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值