jdk源码之ArrayList

概要

  • 类继承关系

java.lang.Object
java.util.AbstractCollection
java.util.AbstractList
java.util.ArrayList

  • 定义

public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable {
}

实现

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

public ArrayList(int initialCapacity) {    
  if (initialCapacity > 0) {        
    this.elementData = new Object[initialCapacity];    
  } else if (initialCapacity == 0) {        
    this.elementData = EMPTY_ELEMENTDATA;    
  } else {        
    throw new IllegalArgumentException("Illegal Capacity: "+                                           initialCapacity);    
  }
}

由代码可知,ArrayList采用数组方式存放对象。无参构造器创建一个空Object数组

private static final Object[] EMPTY_ELEMENTDATA = {};

  • 插入:add(E)
    add方法其实就是给数组中某元素赋值为传入的对象,但add时有个明显的问题是,数组满了怎么办?我们接着往下看。
public boolean add(E e) {    
  ensureCapacityInternal(size + 1);  // Increments modCount!!    
  elementData[size++] = e;    
  return true;
}

ensureCapacityInternal函数的作用是保证数组大小是够用的。

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

参数传入数组的size + 1, 如果数组为空数组,则将minCapacity设为10或者minCapacity中的大值

private static final int DEFAULT_CAPACITY = 10;

函数ensureExplicitCapacity用来产生明确的容量, 如果minCapacity大于数组大小,则进行扩容。

private void ensureExplicitCapacity(int minCapacity) {    
  modCount++;    

  // overflow-conscious code    
  if (minCapacity - elementData.length > 0)        
    grow(minCapacity);
}

扩容代码如下:

private void grow(int minCapacity) {    
  // overflow-conscious code    
  int oldCapacity = elementData.length;    
  int newCapacity = oldCapacity + (oldCapacity >> 1);    
  if (newCapacity - minCapacity < 0)        
    newCapacity = minCapacity;    
  if (newCapacity - MAX_ARRAY_SIZE > 0)        
    newCapacity = hugeCapacity(minCapacity);    
  // minCapacity is usually close to size, so this is a win:    
  elementData = Arrays.copyOf(elementData, newCapacity);
}

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

首先产生新的数组大小为原来的1.5倍,若新的容量仍小于minCapacity,则minCapacity为新的容量,得出新的容量值后,调用Arrays.copyOf来生成新的数组对象,如想调整容量的生长策略,可继承ArrayList, 并覆写ensureCapacity方法。

在Collection中增加对象时,ArrayList还提供add(int, E)这样的方法,允许将元素直接插入到int位置。它要将当前数组的对象进行一次复制,即将目前index及其后的数据都往后挪一位,该方式要多一次复制数组的代价。

public void add(int index, E element) {    
  rangeCheckForAdd(index);    
  ensureCapacityInternal(size + 1);  // Increments modCount!!    
  System.arraycopy(elementData, index, elementData, index + 1, size - index);    
  elementData[index] = element;    size++;
}
  • 删除:remove(E)
    先上代码:
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;
}

如果要删除的对象为null, 循环遍历整个数组,找到为null值的元素,调用fastRemove删除相应位置的对象。

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
}

又代码可知,fastRemove是一次数组的复制,将index后的对象统一向前移动一位,将最后一位设为null, 释放此对象的引用。

若对象非null, 则通过equals来进行比较,同样通过fastRemove来删除元素。

  • 获取单个对象:get(int)
public E get(int index) {    
  rangeCheck(index);    
  return elementData(index);
}

先做数组范围检查,在返回对象。

  • 遍历对象:iterator
public Iterator iterator() {    return new Itr();}

每次调用iterator方法时,都会new一个Itr的实例。
当调用此实例的hasNext方法时,比较当前指向的数组的位置是否和数组中已有元素大小相等,如相等返回false,否则返回true。
、、、
public boolean hasNext() {
return cursor != size; // cursor标识下一个返回元素的位置
}
、、、

当调用实例的next方法时,首先比较在创建此Iterator时获取的modCount与当前的modCount,如果不等,则说明在获取next元素时,发生了对集合大小产生影响(新增、删除)的动作。当发生这种情况时,则抛出ConcurrentModificationException。

  • 判断对象时候存在:contains(E)
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;
}

如果E为null,则直接判断已有元素是否为null, 否则通过判断E.equals和元素是否相等。

  • transient
transient Object[] elementData; // non-private to simplify nested class access

声明为transient后,这个字段不会被序列化。

  • SuppressWarnings
@SuppressWarnings("unchecked")

告诉编译器,对特定类型的warning保持沉默。

注:

  1. ArrayList基于数组实现,无容量的限制。
  2. ArrayList插入元素时可能要扩容,删除时并不会减小数组的容量。
  3. 若希望缩小数组容量,可以调用ArrayList的trimToSize()
public void trimToSize() {    
  modCount++;    
    if (size < elementData.length) {        
      elementData = (size == 0)          
        ? EMPTY_ELEMENTDATA          : Arrays.copyOf(elementData, size);    
    }
}
  1. ArrayList非线程安全。

你可能感兴趣的:(jdk源码之ArrayList)