从源码角度看java之ArrayList

标签: java

ArrayList继承AbstractList并实现List, RandomAccess,Cloneable,java.io.Serializable接口

private static final int DEFAULT_CAPACITY = 10; 

解析:默认容量

private static final Object[] EMPTY_ELEMENTDATA = {}; 

解析:空对象数组

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

解析:默认大小的空对象数组

transient Object[] elementData; 

解析:数组缓存变量,ArrayList的容量是这个数组缓存变量的长度,关键字transient表示它的值不需要维持,不参与序列化

private int size; 

**解析:**ArrayList大小

 public ArrayList(int initialCapacity) {
     // 如果初始化时ArrayList大小大于0  
     if (initialCapacity > 0) {
     // new一个该大小的object数组赋给elementData 
     this.elementData = new Object[initialCapacity];
     } else if (initialCapacity == 0) {
     // 将空数组赋给elementData
     this.elementData = EMPTY_ELEMENTDATA;
     } else {
     //抛出非法异常,比如说initialCapacity<0
     throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
     }
}

解析:构造方法 => 创建容量大小为initialCapacity的空的list

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

解析:构建方法=>创建一个默认长度(10)的空list

public ArrayList(Collectionextends E> c) {
//将c容器转换为object类型的数组
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

解析:带参数Collection构造方法,Collection有一下类型:

  • List:元素可以重复的容器
  • Set: 元素不可重复的容器
  • Queue:结构是一个队列,先进先出

(注意:map也是经常用的集合类,但却没有实现Collection接口,map源码将在以后章节进行解析)

这里是将一个Collection实现类的对象转换为一个ArrayList,c容器装的内容必须为ArrayList装的内容的子类。很好奇什么情况下会出现elementData.getClass() != Object[].class,于是就查看了一下资料说java的一個bug 6260652,toArray() 有可能不會返回Object[]類型。Arrays.copyOf方法最终会调用System.arraycopy实现对数组的复制。

public void trimToSize() {
 //modCount是从类 java.util.AbstractList 继承的字段,防止在多线程操作的情况下,List发生结构性的变化
        modCount++;
        if (size < elementData.length) {
        // 重新将elementData设置大小为size 
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

解析:

  • length:ArrayList申请的内容空间长度
  • size:ArrayList元素的个数

其中length > size,trimToSize方法就是剔除了为null的元素,将ArrayList的容量设置为当前size的大小,实现容量的压缩

//要分配的数组的最大大小
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//long int的最大值
public static final int   MAX_VALUE = 0x7fffffff;

//得到最小扩容量
public void ensureCapacity(int minCapacity) {
//如果elementData为空,minExpand取0,否则去默认容量10
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY;
        if (minCapacity > minExpand) {
        //扩容
            ensureExplicitCapacity(minCapacity);
        }
}

//得到最小扩容量
private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //取最大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //扩容
        ensureExplicitCapacity(minCapacity);
    }

//判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // 如果minCapacity大于elementData.length
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
}


//动态扩容的核心方法
private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
//新数组容量
        int newCapacity = oldCapacity + (oldCapacity >> 1);
// 判断新数组的容量够不够,
//够了就直接使用这个长度创建新数组,
//不够就将数组长度设置为需要的长度  
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
}

 private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) 
           throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
}

解析:最后grow()方法中

  • oldCapacity >> 1表示oldCapacity 右移一位,其效果相当于oldCapacity /2,即ArrayList**默认扩容至1.5倍**
  • 调用Arrays.copyOf方法将elementData数组指向新的容量为newCapacity的连续空间并将elementData的数据复制到新的内存空间
public int size() {return size;}

解析:返回ArrayList元素个数

 public boolean isEmpty() {return size == 0;}

解析:判断ArrayList是否为空

public boolean contains(Object o) {
        return indexOf(o) >= 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;
}

解析:对象o在ArrayList中的下标位置,如果存在返回位置i,不存在返回-1,如果o为空返回0

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的最后一个位置,从后向前遍历,得到第一个出现对象o的位置,不存在则返回-1

 public Object clone() {
        try {
    // 调用父类Object类的clone方法得到一个ArrayList副本  
            ArrayList> v = (ArrayList>) super.clone();
    //将原有对象的数据导入到新创建的对象中。
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;  //初始化modCount
    //返回副本
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

**解析:**clone() 属于Object里面的方法,创建一个对象,然后将原有对象的数据导入到新创建的数据中。

public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

解析:将list转化为一个数组,直接调用Arrays类的copyOf方法

public  T[] toArray(T[] a) { 
//如果a的长度小于ArrayList的长度,直接调用Arrays类的copyOf,返回一个比a数组长度要大的新数组,里面元素就是ArrayList里面的元素
        if (a.length < size)
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
//如果a的长度比ArrayList的长度大,那么就调用System.arraycopy,将ArrayList的elementData数组赋值到a数组,然后把a数组的size位置赋值为空。        
       System.arraycopy(elementData, 0, a, 0, size);
       if (a.length > size)
            a[size] = null;
        return a;
    }

解析:将ArrayList里面的元素赋值到一个数组中去

private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

解析:检查是否越界,如果是抛出IndexOutOfBoundsException异常

public E get(int index) {
        rangeCheck(index); 
        return elementData(index);
    }

解析: 先检查是否越界,然后返回ArrayList的elementData数组index位置的元素。

public E set(int index, E element) {
        rangeCheck(index);
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
}

解析: 先检查是否越界,然后设置elementData数组index位置的元素为element。

public boolean add(E e) {
       ensureCapacityInternal(size + 1);  // Increments modCount!!
      elementData[size++] = e;
      return true;
}

解析:扩容后将e赋值给elementData的size+1的位置

public void add(int index, E element) {
       //判断是否越界
        rangeCheckForAdd(index);
      //扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
     // 将elementData从index位置开始,复制到elementData的index+1开始的连续空间,size - index表示复制的元素的个数
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
}

解析:将特定元素element插入ArrayList的index位置

public E remove(int index) {
//查看是否越界
        rangeCheck(index);
//对ArrayList进行删改时需要自增1
        modCount++;
// 读取index位置的值 
        E oldValue = elementData(index);
// 获取index位置开始到最后一个位置的个数  
        int numMoved = size - index - 1;
        if (numMoved > 0)
// 将elementData数组index+1位置开始拷贝到elementData从index开始的空间  
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
// 使size-1 ,设置elementData的size位置为空,让GC来清理内存空间                               
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
    }

解析:在ArrayList的移除index位置的元素。

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; // clear to let GC do its work
    }
public boolean remove(Object o) {
        //判断o是否为空,如果为空
        if (o == null) {
            for (int index = 0; index < size; index++)
            //将第一个出现为null的值移除掉
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        //如果不为空
        } else {
            for (int index = 0; index < size; index++)
            //将第一个出现对象o的值移除掉
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

解析:在ArrayList的移除对象为O的元素。

public void clear() {
        modCount++;
        // clear to let GC do its work
        for (int i = 0; i < size; i++)
        //将elementData[i]置空,让GC来清理内存空间
                elementData[i] = null;
        //将size置0
        size = 0;
    }

解析:将list里面的所有元素移除,将会返回一个空的list。clear操作并不是从空间内删除,只是设置为null值,然后等待垃圾回收机制来回收,把size设置为0,以便我们不会浏览到null值的内存空间。

public boolean addAll(Collection c) {
        //将c转换为数组
        Object[] a = c.toArray();
        //新增的长度
        int numNew = a.length;
        //扩容至size + numNew长度
        ensureCapacityInternal(size + numNew);  // Increments modCount
       //将a的第0位开始拷贝至elementData的size位开始,拷贝长度为numNew   
        System.arraycopy(a, 0, elementData, size, numNew);
       //size增加长度numNew
        size += numNew;
       //如果c为空,返回false,c不为空,返回true  
        return numNew != 0;
    }

解析:将Collection c的全部元素添加到ArrayList中。

public boolean addAll(int index, Collection c) {
        // 判断index大于size或者是小于0,如果是,则抛出IndexOutOfBoundsException异常  
        rangeCheckForAdd(index);
        //将c转换为数组
        Object[] a = c.toArray();
        int numNew = a.length;
        // 扩容至size + numNew 
        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;
}
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;
 }

解析:从第index位开始,将c全部拷贝到ArrayList

private boolean batchRemove(Collection c, boolean complement) {
        final Object[] elementData = this.elementData;  
     // 定义两个变量w,r,同时右移     
    int r = 0, w = 0;  
    boolean modified = false;  
    try {  
         // r右移  
        for (; r < size; r++)  
              // 如果c中不包含elementData[r]这个元素  
            if (c.contains(elementData[r]) == complement)  
                  // 则直接将r位置的元素赋值给w位置的元素,w自增  
                elementData[w++] = elementData[r];  
    } finally {  
        // 防止抛出异常导致上面r的右移过程没完成  
        if (r != size) {  
              // 将r未右移完成的位置的元素赋值给w右边位置的元素  
            System.arraycopy(elementData, r,  
                             elementData, w,  
                             size - r);  
              // 修改w值增加size-r  
            w += size - r;  
        }  
        if (w != size) {  
            // 如果有被覆盖掉的元素,则将w后面的元素都赋值为null  
            for (int i = w; i < size; i++)  
                elementData[i] = null;  
            modCount += size - w;  
              // 修改size为w  
            size = w;  
            modified = true;  
        }  
    }  
    return modified;  
    }

解析:根据complement值,将ArrayList中包含c中元素的元素删除或者保留。

 public boolean removeAll(Collection c) {
        //如果c为null抛出NullPointerException异常
        Objects.requireNonNull(c);
      //调用batchRemove将list中存在于Collection c的元素移除
        return batchRemove(c, false);
 }

解析:将list中存在于Collection c的元素移除

public boolean retainAll(Collection c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

解析:将list中存在于Collection c的元素保留

你可能感兴趣的:(java)