ArrayList源码分析

一、类结构

ArrayList源码分析_第1张图片
List,Set,Queue等均继承自Collection接口。
二、属性
非常简单就2个属性。
private transient Object[] elementData;
private int size;

三、方法
提供了增删该查方法,代码都比较简单。
大量使用了System.arraycopy(elementData, index, elementData, index + 1,
       size - index);
这个native方法。
第1个elementData:原始数组。
index:原始数组的起始位置
第2个elementData:目的数据。
index+1:目标数组的起始位置。
size - index:要拷贝的长度。
四、扩容
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);
}
   }

ArrayList的方法add时,先执行这个方法判断是否达到了容量的上限,容量的上限是elementData.length,而当前的数据量是size,如果超过了容量上限,则通过
int newCapacity = (oldCapacity * 3)/2 + 1;计算新的容量上限,
然后通过elementData = Arrays.copyOf(elementData, newCapacity);将原有数据拷贝到容量为newCapacity的新数组中。Arrays.copyOf最终执行的是下面的方法。
Arrays.java
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}


所以如果能预知大小的情况下,最好是设置好ArrayList的初始值,这样可以避免ArrayList的频繁扩容造成的性能损耗。
五、大小限制
ArrayList能存放的最大数量取决于它的int size属性,所以最大值是Integer.MAX_VALUE(2147483647)。
六、序列化设计
private transient Object[] elementData;
transient关键字的意思是不进行序列化,但是ArrayList又实现了接口Serializable,貌似有点矛盾啊,既然它的内部数据结构不能序列化,那ArrayList是如何实现序列化的呢。
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<size; i++)
           s.writeObject(elementData[i]);

if (modCount != expectedModCount) {
           throw new ConcurrentModificationException();
       }

   }

 
    private void readObject(java.io.ObjectInputStream s)
       throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();

       // Read in array length and allocate array
       int arrayLength = s.readInt();
       Object[] a = elementData = new Object[arrayLength];

// Read in all elements in the proper order.
for (int i=0; i<size; i++)
           a[i] = s.readObject();
   }

答案就在这里,它实现了readObject和writeObject方法,如果不实现他们就走默认的ObjectOutputStream的defaultWriteObject方法,通过实现这两个方法可以自定义序列化和反序列化的规则。
注意其中用的是i<size,而不是i<elementData.length,这样就保证了只序列化真实有效的数据,避免浪费,这也就是将elementData设置为transient的原因吧。
七、modCount
ArrayList的add和remove等改变结构的方法都执行了代码modCount++,这是干什么用的呢?
int expectedModCount = modCount;

public boolean hasNext() {
           return cursor != size();
}

public E next() {
           checkForComodification();
    try {
   E next = get(cursor);
   lastRet = cursor++;
   return next;
    } catch (IndexOutOfBoundsException e) {
   checkForComodification();
   throw new NoSuchElementException();
    }
}

AbstractList中通过next()进行遍历时,会先执行checkForComodification()方法,该方法
final void checkForComodification() {
    if (modCount != expectedModCount)
   throw new ConcurrentModificationException();
}
   }

如果不相等的话就会抛出ConcurrentModificationException异常,也就是不允许一个线程遍历的时候其他线程修改这个ArrayList。
抛异常示例代码:
public class Tester {
    public static void main(String[] args) throws Exception{
       List<String> list = new ArrayList<String>();
       for(long i=0;i<10;i++){
            list.add(i+"");
       }
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            list.add("haha");
            String it = iterator.next();
            System.out.println(it);
        }
    }


}

八、同Vector区别
Vector同ArrayList的实现基本上差不多,只是Vector是线程安全的方法前面都加了synchronized,另外Vector允许设置capacityIncrement,默认是0,如果等于0的话,以每次2倍的速度增长。
  public synchronized E get(int index) {
if (index >= elementCount)
    throw new ArrayIndexOutOfBoundsException(index);

return (E)elementData[index];
   }

九、CopyOnWriteArrayList
CopyOnWriteArrayList是并发包中的ArrayList的一个版本,它读不加锁,写加锁,非常适用于读多写少且允许部分脏数据的场景。
  public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();//加锁
try {
    Object[] elements = getArray();
    int len = elements.length;
//每次都创建一个新的数组。
    Object[] newElements = Arrays.copyOf(elements, len + 1);
    newElements[len] = e;
    setArray(newElements);
    return true;
} finally {
    lock.unlock();//解锁
}
   }

你可能感兴趣的:(ArrayList)