数据结构之ArrayList

来源:互联网 发布:图像压缩编码编程 编辑:程序博客网 时间:2024/06/10 22:02

直接上JDK源码

ArrayList<E>源代码

public class ArrayList extends AbstractList        implements List, RandomAccess, Cloneable, java.io.Serializable{    private static final long serialVersionUID = 8683452581122892189L;    private static final int DEFAULT_CAPACITY = 10;    private static final Object[] EMPTY_ELEMENTDATA = {};    transient Object[] elementData; // non-private to simplify nested class access    private int size;    public ArrayList(int initialCapacity) {        super();        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal Capacity: "+                                               initialCapacity);        this.elementData = new Object[initialCapacity];    }    public ArrayList() {        super();        this.elementData = EMPTY_ELEMENTDATA;    }    public ArrayList(Collection c) {        elementData = c.toArray();        size = elementData.length;        // c.toArray might (incorrectly) not return Object[] (see 6260652)        if (elementData.getClass() != Object[].class)            elementData = Arrays.copyOf(elementData, size, Object[].class);    }    public void trimToSize() {        modCount++;        if (size < elementData.length) {            elementData = Arrays.copyOf(elementData, size);        }    }    public void ensureCapacity(int minCapacity) {        int minExpand = (elementData != EMPTY_ELEMENTDATA)            // any size if real element table            ? 0            // larger than default for empty table. It's already supposed to be            // at default size.            : DEFAULT_CAPACITY;        if (minCapacity > minExpand) {            ensureExplicitCapacity(minCapacity);        }    }    private void ensureCapacityInternal(int minCapacity) {        if (elementData == EMPTY_ELEMENTDATA) {            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);        }        ensureExplicitCapacity(minCapacity);    }    private void ensureExplicitCapacity(int minCapacity) {        modCount++;        // overflow-conscious code        if (minCapacity - elementData.length > 0)            grow(minCapacity);    }    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;    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;    }    public int size() {        return size;    }    public boolean isEmpty() {        return size == 0;    }    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;    }    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;    }    public Object clone() {        try {            ArrayList v = (ArrayList) super.clone();            v.elementData = Arrays.copyOf(elementData, size);            v.modCount = 0;            return v;        } catch (CloneNotSupportedException e) {            // this shouldn't happen, since we are Cloneable            throw new InternalError(e);        }    }    public Object[] toArray() {        return Arrays.copyOf(elementData, size);    }    @SuppressWarnings("unchecked")    public  T[] toArray(T[] a) {        if (a.length < size)            // Make a new array of a's runtime type, but my contents:            return (T[]) Arrays.copyOf(elementData, size, a.getClass());        System.arraycopy(elementData, 0, a, 0, size);        if (a.length > size)            a[size] = null;        return a;    }    @SuppressWarnings("unchecked")    E elementData(int index) {        return (E) elementData[index];    }    public E get(int index) {        rangeCheck(index);        return elementData(index);    }    public E set(int index, E element) {        rangeCheck(index);        E oldValue = elementData(index);        elementData[index] = element;        return oldValue;    }    public boolean add(E e) {        ensureCapacityInternal(size + 1);  // Increments modCount!!        elementData[size++] = e;        return true;    }    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++;    }    public E remove(int index) {        rangeCheck(index);        modCount++;        E oldValue = elementData(index);        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        return oldValue;    }    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;    }    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 void clear() {        modCount++;        // clear to let GC do its work        for (int i = 0; i < size; i++)            elementData[i] = null;        size = 0;    }    public boolean addAll(Collection c) {        Object[] a = c.toArray();        int numNew = a.length;        ensureCapacityInternal(size + numNew);  // Increments modCount        System.arraycopy(a, 0, elementData, size, numNew);        size += numNew;        return numNew != 0;    }    public boolean addAll(int index, Collection c) {        rangeCheckForAdd(index);        Object[] a = c.toArray();        int numNew = a.length;        ensureCapacityInternal(size + numNew);  // Increments modCount        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;    }    protected void removeRange(int fromIndex, int toIndex) {        modCount++;        int numMoved = size - toIndex;        System.arraycopy(elementData, toIndex, elementData, fromIndex,                         numMoved);        // clear to let GC do its work        int newSize = size - (toIndex-fromIndex);        for (int i = newSize; i < size; i++) {            elementData[i] = null;        }        size = newSize;    }    private void rangeCheck(int index) {        if (index >= size)            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));    }    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;    }    public boolean removeAll(Collection c) {        Objects.requireNonNull(c);        return batchRemove(c, false);    }    public boolean retainAll(Collection c) {        Objects.requireNonNull(c);        return batchRemove(c, true);    }    private boolean batchRemove(Collection c, boolean complement) {        final Object[] elementData = this.elementData;        int r = 0, w = 0;        boolean modified = false;        try {            for (; r < size; r++)                if (c.contains(elementData[r]) == complement)                    elementData[w++] = elementData[r];        } finally {            // Preserve behavioral compatibility with AbstractCollection,            // even if c.contains() throws.            if (r != size) {                System.arraycopy(elementData, r,                                 elementData, w,                                 size - r);                w += size - r;            }            if (w != size) {                // clear to let GC do its work                for (int i = w; i < size; i++)                    elementData[i] = null;                modCount += size - w;                size = w;                modified = true;            }        }        return modified;    }    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 size as capacity for behavioural compatibility with clone()        s.writeInt(size);        // Write out all elements in the proper order.        for (int i=0; i
AbstractList<E>源代码

public abstract class AbstractList extends AbstractCollection implements List {    protected AbstractList() {    }    public boolean add(E e) {        add(size(), e);        return true;    }    abstract public E get(int index);    public E set(int index, E element) {        throw new UnsupportedOperationException();    }    public void add(int index, E element) {        throw new UnsupportedOperationException();    }    public E remove(int index) {        throw new UnsupportedOperationException();    }    public int indexOf(Object o) {        ListIterator it = listIterator();        if (o==null) {            while (it.hasNext())                if (it.next()==null)                    return it.previousIndex();        } else {            while (it.hasNext())                if (o.equals(it.next()))                    return it.previousIndex();        }        return -1;    }    public int lastIndexOf(Object o) {        ListIterator it = listIterator(size());        if (o==null) {            while (it.hasPrevious())                if (it.previous()==null)                    return it.nextIndex();        } else {            while (it.hasPrevious())                if (o.equals(it.previous()))                    return it.nextIndex();        }        return -1;    }    public void clear() {        removeRange(0, size());    }    public boolean addAll(int index, Collection c) {        rangeCheckForAdd(index);        boolean modified = false;        for (E e : c) {            add(index++, e);            modified = true;        }        return modified;    }    public Iterator iterator() {        return new Itr();    }    public ListIterator listIterator() {        return listIterator(0);    }    public ListIterator listIterator(final int index) {        rangeCheckForAdd(index);        return new ListItr(index);    }    private class Itr implements Iterator {        int cursor = 0;        int lastRet = -1;        int expectedModCount = modCount;        public boolean hasNext() {            return cursor != size();        }        public E next() {            checkForComodification();            try {                int i = cursor;                E next = get(i);                lastRet = i;                cursor = i + 1;                return next;            } catch (IndexOutOfBoundsException e) {                checkForComodification();                throw new NoSuchElementException();            }        }        public void remove() {            if (lastRet < 0)                throw new IllegalStateException();            checkForComodification();            try {                AbstractList.this.remove(lastRet);                if (lastRet < cursor)                    cursor--;                lastRet = -1;                expectedModCount = modCount;            } catch (IndexOutOfBoundsException e) {                throw new ConcurrentModificationException();            }        }        final void checkForComodification() {            if (modCount != expectedModCount)                throw new ConcurrentModificationException();        }    }    private class ListItr extends Itr implements ListIterator {        ListItr(int index) {            cursor = index;        }        public boolean hasPrevious() {            return cursor != 0;        }        public E previous() {            checkForComodification();            try {                int i = cursor - 1;                E previous = get(i);                lastRet = cursor = i;                return previous;            } catch (IndexOutOfBoundsException e) {                checkForComodification();                throw new NoSuchElementException();            }        }        public int nextIndex() {            return cursor;        }        public int previousIndex() {            return cursor-1;        }        public void set(E e) {            if (lastRet < 0)                throw new IllegalStateException();            checkForComodification();            try {                AbstractList.this.set(lastRet, e);                expectedModCount = modCount;            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }        public void add(E e) {            checkForComodification();            try {                int i = cursor;                AbstractList.this.add(i, e);                lastRet = -1;                cursor = i + 1;                expectedModCount = modCount;            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }    }    public List subList(int fromIndex, int toIndex) {        return (this instanceof RandomAccess ?                new RandomAccessSubList<>(this, fromIndex, toIndex) :                new SubList<>(this, fromIndex, toIndex));    }    public boolean equals(Object o) {        if (o == this)            return true;        if (!(o instanceof List))            return false;        ListIterator e1 = listIterator();        ListIterator e2 = ((List) o).listIterator();        while (e1.hasNext() && e2.hasNext()) {            E o1 = e1.next();            Object o2 = e2.next();            if (!(o1==null ? o2==null : o1.equals(o2)))                return false;        }        return !(e1.hasNext() || e2.hasNext());    }    public int hashCode() {        int hashCode = 1;        for (E e : this)            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());        return hashCode;    }    protected void removeRange(int fromIndex, int toIndex) {        ListIterator it = listIterator(fromIndex);        for (int i=0, n=toIndex-fromIndex; i size())            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));    }    private String outOfBoundsMsg(int index) {        return "Index: "+index+", Size: "+size();    }}class SubList extends AbstractList {    private final AbstractList l;    private final int offset;    private int size;    SubList(AbstractList list, int fromIndex, int toIndex) {        if (fromIndex < 0)            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);        if (toIndex > list.size())            throw new IndexOutOfBoundsException("toIndex = " + toIndex);        if (fromIndex > toIndex)            throw new IllegalArgumentException("fromIndex(" + fromIndex +                                               ") > toIndex(" + toIndex + ")");        l = list;        offset = fromIndex;        size = toIndex - fromIndex;        this.modCount = l.modCount;    }    public E set(int index, E element) {        rangeCheck(index);        checkForComodification();        return l.set(index+offset, element);    }    public E get(int index) {        rangeCheck(index);        checkForComodification();        return l.get(index+offset);    }    public int size() {        checkForComodification();        return size;    }    public void add(int index, E element) {        rangeCheckForAdd(index);        checkForComodification();        l.add(index+offset, element);        this.modCount = l.modCount;        size++;    }    public E remove(int index) {        rangeCheck(index);        checkForComodification();        E result = l.remove(index+offset);        this.modCount = l.modCount;        size--;        return result;    }    protected void removeRange(int fromIndex, int toIndex) {        checkForComodification();        l.removeRange(fromIndex+offset, toIndex+offset);        this.modCount = l.modCount;        size -= (toIndex-fromIndex);    }    public boolean addAll(Collection c) {        return addAll(size, c);    }    public boolean addAll(int index, Collection c) {        rangeCheckForAdd(index);        int cSize = c.size();        if (cSize==0)            return false;        checkForComodification();        l.addAll(offset+index, c);        this.modCount = l.modCount;        size += cSize;        return true;    }    public Iterator iterator() {        return listIterator();    }    public ListIterator listIterator(final int index) {        checkForComodification();        rangeCheckForAdd(index);        return new ListIterator() {            private final ListIterator i = l.listIterator(index+offset);            public boolean hasNext() {                return nextIndex() < size;            }            public E next() {                if (hasNext())                    return i.next();                else                    throw new NoSuchElementException();            }            public boolean hasPrevious() {                return previousIndex() >= 0;            }            public E previous() {                if (hasPrevious())                    return i.previous();                else                    throw new NoSuchElementException();            }            public int nextIndex() {                return i.nextIndex() - offset;            }            public int previousIndex() {                return i.previousIndex() - offset;            }            public void remove() {                i.remove();                SubList.this.modCount = l.modCount;                size--;            }            public void set(E e) {                i.set(e);            }            public void add(E e) {                i.add(e);                SubList.this.modCount = l.modCount;                size++;            }        };    }    public List subList(int fromIndex, int toIndex) {        return new SubList<>(this, fromIndex, toIndex);    }    private void rangeCheck(int index) {        if (index < 0 || index >= size)            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));    }    private void rangeCheckForAdd(int index) {        if (index < 0 || index > size)            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));    }    private String outOfBoundsMsg(int index) {        return "Index: "+index+", Size: "+size;    }    private void checkForComodification() {        if (this.modCount != l.modCount)            throw new ConcurrentModificationException();    }}class RandomAccessSubList extends SubList implements RandomAccess {    RandomAccessSubList(AbstractList list, int fromIndex, int toIndex) {        super(list, fromIndex, toIndex);    }    public List subList(int fromIndex, int toIndex) {        return new RandomAccessSubList<>(this, fromIndex, toIndex);    }}

AbstractCollection<E>源代码

public abstract class AbstractCollection implements Collection {    protected AbstractCollection() {    }    public abstract Iterator iterator();    public abstract int size();    public boolean isEmpty() {        return size() == 0;    }    public boolean contains(Object o) {        Iterator it = iterator();        if (o==null) {            while (it.hasNext())                if (it.next()==null)                    return true;        } else {            while (it.hasNext())                if (o.equals(it.next()))                    return true;        }        return false;    }    public Object[] toArray() {        // Estimate size of array; be prepared to see more or fewer elements        Object[] r = new Object[size()];        Iterator it = iterator();        for (int i = 0; i < r.length; i++) {            if (! it.hasNext()) // fewer elements than expected                return Arrays.copyOf(r, i);            r[i] = it.next();        }        return it.hasNext() ? finishToArray(r, it) : r;    }    @SuppressWarnings("unchecked")    public  T[] toArray(T[] a) {        // Estimate size of array; be prepared to see more or fewer elements        int size = size();        T[] r = a.length >= size ? a :                  (T[])java.lang.reflect.Array                  .newInstance(a.getClass().getComponentType(), size);        Iterator it = iterator();        for (int i = 0; i < r.length; i++) {            if (! it.hasNext()) { // fewer elements than expected                if (a == r) {                    r[i] = null; // null-terminate                } else if (a.length < i) {                    return Arrays.copyOf(r, i);                } else {                    System.arraycopy(r, 0, a, 0, i);                    if (a.length > i) {                        a[i] = null;                    }                }                return a;            }            r[i] = (T)it.next();        }        // more elements than expected        return it.hasNext() ? finishToArray(r, it) : r;    }    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;    @SuppressWarnings("unchecked")    private static  T[] finishToArray(T[] r, Iterator it) {        int i = r.length;        while (it.hasNext()) {            int cap = r.length;            if (i == cap) {                int newCap = cap + (cap >> 1) + 1;                // overflow-conscious code                if (newCap - MAX_ARRAY_SIZE > 0)                    newCap = hugeCapacity(cap + 1);                r = Arrays.copyOf(r, newCap);            }            r[i++] = (T)it.next();        }        // trim if overallocated        return (i == r.length) ? r : Arrays.copyOf(r, i);    }    private static int hugeCapacity(int minCapacity) {        if (minCapacity < 0) // overflow            throw new OutOfMemoryError                ("Required array size too large");        return (minCapacity > MAX_ARRAY_SIZE) ?            Integer.MAX_VALUE :            MAX_ARRAY_SIZE;    }    public boolean add(E e) {        throw new UnsupportedOperationException();    }    public boolean remove(Object o) {        Iterator it = iterator();        if (o==null) {            while (it.hasNext()) {                if (it.next()==null) {                    it.remove();                    return true;                }            }        } else {            while (it.hasNext()) {                if (o.equals(it.next())) {                    it.remove();                    return true;                }            }        }        return false;    }    public boolean containsAll(Collection c) {        for (Object e : c)            if (!contains(e))                return false;        return true;    }    public boolean addAll(Collection c) {        boolean modified = false;        for (E e : c)            if (add(e))                modified = true;        return modified;    }    public boolean removeAll(Collection c) {        Objects.requireNonNull(c);        boolean modified = false;        Iterator it = iterator();        while (it.hasNext()) {            if (c.contains(it.next())) {                it.remove();                modified = true;            }        }        return modified;    }    public boolean retainAll(Collection c) {        Objects.requireNonNull(c);        boolean modified = false;        Iterator it = iterator();        while (it.hasNext()) {            if (!c.contains(it.next())) {                it.remove();                modified = true;            }        }        return modified;    }    public void clear() {        Iterator it = iterator();        while (it.hasNext()) {            it.next();            it.remove();        }    }    public String toString() {        Iterator it = iterator();        if (! it.hasNext())            return "[]";        StringBuilder sb = new StringBuilder();        sb.append('[');        for (;;) {            E e = it.next();            sb.append(e == this ? "(this Collection)" : e);            if (! it.hasNext())                return sb.append(']').toString();            sb.append(',').append(' ');        }    }}
List的源代码就不再叙述

ArrayList是动态数组,用MSDN中的说法,就是Array的复杂版本。ArrayList可以动态的增加和减少元素,并且能灵活的设置数组的大小。

注意:

(1)ArrayList是Array的复杂版本ArrayList内部封装了一个Object类型的数组,从一般的意义来说,它和数组没有本质的差别,甚至于ArrayList的许多方法,如Index、IndexOf、Contains、Sort等都是在内部数组的基础上直接调用Array的对应方法。
(2)内部的Object类型的影响对于一般的引用类型来说,这部分的影响不是很大,但是对于值类型来说,往ArrayList里面添加和修改元素,都会引起装箱和拆箱的操作,频繁的操作可能会影响一部分效率。但是恰恰对于大多数人,多数的应用都是使用值类型的数组。消除这个影响是没有办法的,除非你不用它,否则就要承担一部分的效率损失,不过这部分的损失不会很大。
(3)数组扩容这是对ArrayList效率影响比较大的一个因素。每当执行Add、AddRange、Insert、InsertRange等添加元素的方法,都会检查内部数组的容量是否不够了,如果是,它就会以当前容量的两倍来重新构建一个数组,将旧元素Copy到新数组中,然后丢弃旧数组,在这个临界点的扩容操作,应该来说是比较影响效率的。
(4)频繁的调用IndexOf、Contains等方法(Sort、BinarySearch等方法经过优化,不在此列)引起的效率损失首先,我们要明确一点,ArrayList是动态数组,它不包括通过Key或者Value快速访问的算法,所以实际上调用IndexOf、Contains等方法是执行的简单的循环来查找元素,所以频繁的调用此类方法并不比你自己写循环并且稍作优化来的快,如果有这方面的要求,建议使用Hashtable或SortedList等键值对的集合。

总结:

(01) ArrayList 实际上是通过一个数组去保存数据的。当我们构造ArrayList时;若使用默认构造函数,则ArrayList的默认容量大小是10。
(02) 当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=“(原始容量x3)/2 + 1”。
(03) ArrayList的克隆函数,即是将全部元素克隆到一个数组中。
(04) ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写入“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
原创粉丝点击