[关闭]
@xmruibi 2015-02-13T22:22:18.000000Z 字数 6025 阅读 710

ArrayList Summary

Data_Structure


ArrayList

1. Fields:

  1. private transient Object[] elementData;
  2. //** transient is a Java keyword which marks a member variable not to be serialized when it is persisted to streams of bytes.
  3. private int size;
  4. //** size is volumn of ArrayList,but not the length of elementData
  5. protected transient int modCount = 0;
  6. //** This field is inheriented from Abtract List, which is for recording the times of structrual change. Like add(), remove(), addall(), removerange() and clear() can increase the number of modCount. The specific modCout increase operations are in ensureCapacityInternal which is called by add() and addall().

2. Contructors:

  1. /**By given initial length**/
  2. public ArrayList(int initialCapacity) {
  3. super();
  4. if (initialCapacity < 0)
  5. throw new IllegalArgumentException("Illegal Capacity: "+
  6. initialCapacity);
  7. this.elementData = new Object[initialCapacity];
  8. }
  9. /**By default initial length (10)**/
  10. // in newest 1.8 it shows that "this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;"
  11. // with " private static final Object[] EMPTY_ELEMENTDATA = {}; "
  12. // but the length 10 will be initalized when checking the capacity;
  13. public ArrayList() {
  14. this(10);
  15. }
  16. public ArrayList(Collection<? extends E> c) {
  17. elementData = c.toArray();
  18. size = elementData.length;
  19. if (elementData.getClass() != Object[].class)
  20. elementData = Arrays.copyOf(elementData, size, Object[].class);
  21. }

3. Dynamic Capacity Ensurance Mechanism

3.1 ArrayList通过ensureCapacityInternal(int minCapacity)方法实现自身容量的增加,在add()和addAll()方法里面都调用了改方法。

  1. private void ensureCapacityInternal(int minCapacity) {
  2. modCount++;
  3. if (minCapacity - elementData.length > 0)
  4. // minCapacity means the minimal capacity need to be checked
  5. grow(minCapacity);
  6. }

3.2 Grow() method is mainly for capacity expansion, which expands the 1.5 times than orginal capacity each time.

  1. private void grow(int minCapacity) {
  2. int oldCapacity = elementData.length;
  3. int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5 times of array length!!
  4. // newCapacity is allowed
  5. if (newCapacity - minCapacity < 0)
  6. newCapacity = minCapacity;
  7. // newCapacity is larger than MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8)
  8. if (newCapacity - MAX_ARRAY_SIZE > 0)
  9. newCapacity = hugeCapacity(minCapacity);
  10. elementData = Arrays.copyOf(elementData, newCapacity);
  11. }
  12. private static int hugeCapacity(int minCapacity) {
  13. if (minCapacity < 0)
  14. throw new OutOfMemoryError();
  15. return (minCapacity > MAX_ARRAY_SIZE) ?
  16. Integer.MAX_VALUE :
  17. MAX_ARRAY_SIZE;
  18. }
  19. /**This is mainly for checking if the value of minCapacity is overflow**/
  20. private static int hugeCapacity(int minCapacity) {
  21. if (minCapacity < 0) // overflow
  22. throw new OutOfMemoryError();
  23. return (minCapacity > MAX_ARRAY_SIZE) ?
  24. Integer.MAX_VALUE :
  25. MAX_ARRAY_SIZE;
  26. }

3.3 TrimToSize() method is mainly for reduce the lenght to fit the size

  1. public void trimToSize() {
  2. modCount++;
  3. int oldCapacity = elementData.length;
  4. if (size < oldCapacity) {
  5. elementData = Arrays.copyOf(elementData, size);
  6. }
  7. }

4. Add Element

4.1 Add the element in the last of array

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

4.2 Add the element with index

Notice: System.arraycopy is "Native" method which means the quite low level and high efficiency. If arraycopy operated on the same array(like elementData to elementData), the temporary array should be set up for transfer, however it doesn't work when the object is not primitive type, which is only copying the reference.

  1. public void add(int index, E element) {
  2. rangeCheckForAdd(index); // check the input index is inside the arrange
  3. ensureCapacityInternal(size + 1);
  4. System.arraycopy(elementData, index, elementData, index + 1,
  5. size - index);
  6. elementData[index] = element;
  7. size++;
  8. }
  9. private void rangeCheckForAdd(int index) {
  10. if (index > size || index < 0)
  11. throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
  12. }

5. Remove Element

5.1 Remove and return element with index:

  1. public E remove(int index) {
  2. rangeCheck(index);
  3. modCount++;
  4. E oldValue = elementData(index);
  5. int numMoved = size - index - 1; // also can check if the remove is in the last position of array
  6. if (numMoved > 0)
  7. System.arraycopy(elementData, index+1, elementData, index,
  8. numMoved);
  9. // start from index+1, target to start form index(removing index elem), with numMoved length!
  10. elementData[--size] = null;
  11. return oldValue;
  12. }

5.2 Remove with boolean return

Just check if the index-th element on array is null

  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. }
  17. private void fastRemove(int index) {
  18. modCount++;
  19. int numMoved = size - index - 1;
  20. if (numMoved > 0)
  21. System.arraycopy(elementData, index+1, elementData, index,
  22. numMoved);
  23. elementData[--size] = null;
  24. }

6. Batch Operation

6.1 Add All Elements

  1. //directly insert Collection c into 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. //insert Collection c into ArrayList with index pointer
  11. public boolean addAll(int index, Collection<? extends E> c) {
  12. rangeCheckForAdd(index);
  13. Object[] a = c.toArray(); // based on collection to Array
  14. int numNew = a.length;
  15. ensureCapacityInternal(size + numNew); // Increments modCount
  16. int numMoved = size - index;
  17. if (numMoved > 0)
  18. System.arraycopy(elementData, index, elementData, index + numNew,
  19. numMoved);
  20. System.arraycopy(a, 0, elementData, index, numNew);
  21. size += numNew;
  22. return numNew != 0;
  23. }

7. Iterator:

7.0 Initialization

  1. public Iterator<E> iterator() {
  2. return new Itr(); // as the inner class
  3. }

7.1 Fields for iterator

  1. int cursor; // index of next element to return
  2. int lastRet = -1; // index of last element returned; -1 if no such
  3. int expectedModCount = modCount;
  4. //expectedModCount的值为Itr初始化时候ArrayList的modCount的值,前面将过modCount用于记录ArrayList内发生结构性改变的次数,而Itr每次进行next或remove的时候都会去检查expectedModCount值是否还和现在的modCount值一直,从而保证了迭代器和ArrayList内数据的一致性。
  1. public E next() {
  2. checkForComodification();
  3. int i = cursor; // thread safe??
  4. if (i >= size)
  5. throw new NoSuchElementException();
  6. Object[] elementData = ArrayList.this.elementData;
  7. if (i >= elementData.length)
  8. throw new ConcurrentModificationException();
  9. cursor = i + 1;
  10. return (E) elementData[lastRet = i];
  11. }
  12. final void checkForComodification() {
  13. if (modCount != expectedModCount)
  14. throw new ConcurrentModificationException();
  15. }

Conclusion:

  1. Be sure about learning enough knowledge on Array, especially on Array copy operation!
  1. public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
  2. // all position arguments are point to the begining index
  1. Don't confused on several size variables with capacities and array length;
  2. 3.
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注