Home | History | Annotate | Download | only in util
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.util;
     19 
     20 import java.io.IOException;
     21 import java.io.InvalidObjectException;
     22 import java.io.ObjectInputStream;
     23 import java.io.ObjectOutputStream;
     24 import java.io.Serializable;
     25 import java.lang.reflect.Array;
     26 import libcore.util.EmptyArray;
     27 
     28 /**
     29  * ArrayList is an implementation of {@link List}, backed by an array.
     30  * All optional operations including adding, removing, and replacing elements are supported.
     31  *
     32  * <p>All elements are permitted, including null.
     33  *
     34  * <p>This class is a good choice as your default {@code List} implementation.
     35  * {@link Vector} synchronizes all operations, but not necessarily in a way that's
     36  * meaningful to your application: synchronizing each call to {@code get}, for example, is not
     37  * equivalent to synchronizing the list and iterating over it (which is probably what you intended).
     38  * {@link java.util.concurrent.CopyOnWriteArrayList} is intended for the special case of very high
     39  * concurrency, frequent traversals, and very rare mutations.
     40  *
     41  * @param <E> The element type of this list.
     42  * @since 1.2
     43  */
     44 public class ArrayList<E> extends AbstractList<E> implements Cloneable, Serializable, RandomAccess {
     45     /**
     46      * The minimum amount by which the capacity of an ArrayList will increase.
     47      * This tuning parameter controls a time-space tradeoff. This value (12)
     48      * gives empirically good results and is arguably consistent with the
     49      * RI's specified default initial capacity of 10: instead of 10, we start
     50      * with 0 (sans allocation) and jump to 12.
     51      */
     52     private static final int MIN_CAPACITY_INCREMENT = 12;
     53 
     54     /**
     55      * The number of elements in this list.
     56      */
     57     int size;
     58 
     59     /**
     60      * The elements in this list, followed by nulls.
     61      */
     62     transient Object[] array;
     63 
     64     /**
     65      * Constructs a new instance of {@code ArrayList} with the specified
     66      * initial capacity.
     67      *
     68      * @param capacity
     69      *            the initial capacity of this {@code ArrayList}.
     70      */
     71     public ArrayList(int capacity) {
     72         if (capacity < 0) {
     73             throw new IllegalArgumentException("capacity < 0: " + capacity);
     74         }
     75         array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
     76     }
     77 
     78     /**
     79      * Constructs a new {@code ArrayList} instance with zero initial capacity.
     80      */
     81     public ArrayList() {
     82         array = EmptyArray.OBJECT;
     83     }
     84 
     85     /**
     86      * Constructs a new instance of {@code ArrayList} containing the elements of
     87      * the specified collection.
     88      *
     89      * @param collection
     90      *            the collection of elements to add.
     91      */
     92     public ArrayList(Collection<? extends E> collection) {
     93         if (collection == null) {
     94             throw new NullPointerException("collection == null");
     95         }
     96 
     97         Object[] a = collection.toArray();
     98         if (a.getClass() != Object[].class) {
     99             Object[] newArray = new Object[a.length];
    100             System.arraycopy(a, 0, newArray, 0, a.length);
    101             a = newArray;
    102         }
    103         array = a;
    104         size = a.length;
    105     }
    106 
    107     /**
    108      * Adds the specified object at the end of this {@code ArrayList}.
    109      *
    110      * @param object
    111      *            the object to add.
    112      * @return always true
    113      */
    114     @Override public boolean add(E object) {
    115         Object[] a = array;
    116         int s = size;
    117         if (s == a.length) {
    118             Object[] newArray = new Object[s +
    119                     (s < (MIN_CAPACITY_INCREMENT / 2) ?
    120                      MIN_CAPACITY_INCREMENT : s >> 1)];
    121             System.arraycopy(a, 0, newArray, 0, s);
    122             array = a = newArray;
    123         }
    124         a[s] = object;
    125         size = s + 1;
    126         modCount++;
    127         return true;
    128     }
    129 
    130     /**
    131      * Inserts the specified object into this {@code ArrayList} at the specified
    132      * location. The object is inserted before any previous element at the
    133      * specified location. If the location is equal to the size of this
    134      * {@code ArrayList}, the object is added at the end.
    135      *
    136      * @param index
    137      *            the index at which to insert the object.
    138      * @param object
    139      *            the object to add.
    140      * @throws IndexOutOfBoundsException
    141      *             when {@code location < 0 || location > size()}
    142      */
    143     @Override public void add(int index, E object) {
    144         Object[] a = array;
    145         int s = size;
    146         if (index > s || index < 0) {
    147             throwIndexOutOfBoundsException(index, s);
    148         }
    149 
    150         if (s < a.length) {
    151             System.arraycopy(a, index, a, index + 1, s - index);
    152         } else {
    153             // assert s == a.length;
    154             Object[] newArray = new Object[newCapacity(s)];
    155             System.arraycopy(a, 0, newArray, 0, index);
    156             System.arraycopy(a, index, newArray, index + 1, s - index);
    157             array = a = newArray;
    158         }
    159         a[index] = object;
    160         size = s + 1;
    161         modCount++;
    162     }
    163 
    164     /**
    165      * This method controls the growth of ArrayList capacities.  It represents
    166      * a time-space tradeoff: we don't want to grow lists too frequently
    167      * (which wastes time and fragments storage), but we don't want to waste
    168      * too much space in unused excess capacity.
    169      *
    170      * NOTE: This method is inlined into {@link #add(Object)} for performance.
    171      * If you change the method, change it there too!
    172      */
    173     private static int newCapacity(int currentCapacity) {
    174         int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
    175                 MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
    176         return currentCapacity + increment;
    177     }
    178 
    179     /**
    180      * Adds the objects in the specified collection to this {@code ArrayList}.
    181      *
    182      * @param collection
    183      *            the collection of objects.
    184      * @return {@code true} if this {@code ArrayList} is modified, {@code false}
    185      *         otherwise.
    186      */
    187     @Override public boolean addAll(Collection<? extends E> collection) {
    188         Object[] newPart = collection.toArray();
    189         int newPartSize = newPart.length;
    190         if (newPartSize == 0) {
    191             return false;
    192         }
    193         Object[] a = array;
    194         int s = size;
    195         int newSize = s + newPartSize; // If add overflows, arraycopy will fail
    196         if (newSize > a.length) {
    197             int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
    198             Object[] newArray = new Object[newCapacity];
    199             System.arraycopy(a, 0, newArray, 0, s);
    200             array = a = newArray;
    201         }
    202         System.arraycopy(newPart, 0, a, s, newPartSize);
    203         size = newSize;
    204         modCount++;
    205         return true;
    206     }
    207 
    208     /**
    209      * Inserts the objects in the specified collection at the specified location
    210      * in this List. The objects are added in the order they are returned from
    211      * the collection's iterator.
    212      *
    213      * @param index
    214      *            the index at which to insert.
    215      * @param collection
    216      *            the collection of objects.
    217      * @return {@code true} if this {@code ArrayList} is modified, {@code false}
    218      *         otherwise.
    219      * @throws IndexOutOfBoundsException
    220      *             when {@code location < 0 || location > size()}
    221      */
    222     @Override
    223     public boolean addAll(int index, Collection<? extends E> collection) {
    224         int s = size;
    225         if (index > s || index < 0) {
    226             throwIndexOutOfBoundsException(index, s);
    227         }
    228         Object[] newPart = collection.toArray();
    229         int newPartSize = newPart.length;
    230         if (newPartSize == 0) {
    231             return false;
    232         }
    233         Object[] a = array;
    234         int newSize = s + newPartSize; // If add overflows, arraycopy will fail
    235         if (newSize <= a.length) {
    236              System.arraycopy(a, index, a, index + newPartSize, s - index);
    237         } else {
    238             int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
    239             Object[] newArray = new Object[newCapacity];
    240             System.arraycopy(a, 0, newArray, 0, index);
    241             System.arraycopy(a, index, newArray, index + newPartSize, s-index);
    242             array = a = newArray;
    243         }
    244         System.arraycopy(newPart, 0, a, index, newPartSize);
    245         size = newSize;
    246         modCount++;
    247         return true;
    248     }
    249 
    250     /**
    251      * This method was extracted to encourage VM to inline callers.
    252      * TODO: when we have a VM that can actually inline, move the test in here too!
    253      */
    254     static IndexOutOfBoundsException throwIndexOutOfBoundsException(int index, int size) {
    255         throw new IndexOutOfBoundsException("Invalid index " + index + ", size is " + size);
    256     }
    257 
    258     /**
    259      * Removes all elements from this {@code ArrayList}, leaving it empty.
    260      *
    261      * @see #isEmpty
    262      * @see #size
    263      */
    264     @Override public void clear() {
    265         if (size != 0) {
    266             Arrays.fill(array, 0, size, null);
    267             size = 0;
    268             modCount++;
    269         }
    270     }
    271 
    272     /**
    273      * Returns a new {@code ArrayList} with the same elements, the same size and
    274      * the same capacity as this {@code ArrayList}.
    275      *
    276      * @return a shallow copy of this {@code ArrayList}
    277      * @see java.lang.Cloneable
    278      */
    279     @Override public Object clone() {
    280         try {
    281             ArrayList<?> result = (ArrayList<?>) super.clone();
    282             result.array = array.clone();
    283             return result;
    284         } catch (CloneNotSupportedException e) {
    285            throw new AssertionError();
    286         }
    287     }
    288 
    289     /**
    290      * Ensures that after this operation the {@code ArrayList} can hold the
    291      * specified number of elements without further growing.
    292      *
    293      * @param minimumCapacity
    294      *            the minimum capacity asked for.
    295      */
    296     public void ensureCapacity(int minimumCapacity) {
    297         Object[] a = array;
    298         if (a.length < minimumCapacity) {
    299             Object[] newArray = new Object[minimumCapacity];
    300             System.arraycopy(a, 0, newArray, 0, size);
    301             array = newArray;
    302             modCount++;
    303         }
    304     }
    305 
    306     @SuppressWarnings("unchecked") @Override public E get(int index) {
    307         if (index >= size) {
    308             throwIndexOutOfBoundsException(index, size);
    309         }
    310         return (E) array[index];
    311     }
    312 
    313     /**
    314      * Returns the number of elements in this {@code ArrayList}.
    315      *
    316      * @return the number of elements in this {@code ArrayList}.
    317      */
    318     @Override public int size() {
    319         return size;
    320     }
    321 
    322     @Override public boolean isEmpty() {
    323         return size == 0;
    324     }
    325 
    326     /**
    327      * Searches this {@code ArrayList} for the specified object.
    328      *
    329      * @param object
    330      *            the object to search for.
    331      * @return {@code true} if {@code object} is an element of this
    332      *         {@code ArrayList}, {@code false} otherwise
    333      */
    334     @Override public boolean contains(Object object) {
    335         Object[] a = array;
    336         int s = size;
    337         if (object != null) {
    338             for (int i = 0; i < s; i++) {
    339                 if (object.equals(a[i])) {
    340                     return true;
    341                 }
    342             }
    343         } else {
    344             for (int i = 0; i < s; i++) {
    345                 if (a[i] == null) {
    346                     return true;
    347                 }
    348             }
    349         }
    350         return false;
    351     }
    352 
    353     @Override public int indexOf(Object object) {
    354         Object[] a = array;
    355         int s = size;
    356         if (object != null) {
    357             for (int i = 0; i < s; i++) {
    358                 if (object.equals(a[i])) {
    359                     return i;
    360                 }
    361             }
    362         } else {
    363             for (int i = 0; i < s; i++) {
    364                 if (a[i] == null) {
    365                     return i;
    366                 }
    367             }
    368         }
    369         return -1;
    370     }
    371 
    372     @Override public int lastIndexOf(Object object) {
    373         Object[] a = array;
    374         if (object != null) {
    375             for (int i = size - 1; i >= 0; i--) {
    376                 if (object.equals(a[i])) {
    377                     return i;
    378                 }
    379             }
    380         } else {
    381             for (int i = size - 1; i >= 0; i--) {
    382                 if (a[i] == null) {
    383                     return i;
    384                 }
    385             }
    386         }
    387         return -1;
    388     }
    389 
    390     /**
    391      * Removes the object at the specified location from this list.
    392      *
    393      * @param index
    394      *            the index of the object to remove.
    395      * @return the removed object.
    396      * @throws IndexOutOfBoundsException
    397      *             when {@code location < 0 || location >= size()}
    398      */
    399     @Override public E remove(int index) {
    400         Object[] a = array;
    401         int s = size;
    402         if (index >= s) {
    403             throwIndexOutOfBoundsException(index, s);
    404         }
    405         @SuppressWarnings("unchecked") E result = (E) a[index];
    406         System.arraycopy(a, index + 1, a, index, --s - index);
    407         a[s] = null;  // Prevent memory leak
    408         size = s;
    409         modCount++;
    410         return result;
    411     }
    412 
    413     @Override public boolean remove(Object object) {
    414         Object[] a = array;
    415         int s = size;
    416         if (object != null) {
    417             for (int i = 0; i < s; i++) {
    418                 if (object.equals(a[i])) {
    419                     System.arraycopy(a, i + 1, a, i, --s - i);
    420                     a[s] = null;  // Prevent memory leak
    421                     size = s;
    422                     modCount++;
    423                     return true;
    424                 }
    425             }
    426         } else {
    427             for (int i = 0; i < s; i++) {
    428                 if (a[i] == null) {
    429                     System.arraycopy(a, i + 1, a, i, --s - i);
    430                     a[s] = null;  // Prevent memory leak
    431                     size = s;
    432                     modCount++;
    433                     return true;
    434                 }
    435             }
    436         }
    437         return false;
    438     }
    439 
    440     @Override protected void removeRange(int fromIndex, int toIndex) {
    441         if (fromIndex == toIndex) {
    442             return;
    443         }
    444         Object[] a = array;
    445         int s = size;
    446         if (fromIndex >= s) {
    447             throw new IndexOutOfBoundsException("fromIndex " + fromIndex
    448                     + " >= size " + size);
    449         }
    450         if (toIndex > s) {
    451             throw new IndexOutOfBoundsException("toIndex " + toIndex
    452                     + " > size " + size);
    453         }
    454         if (fromIndex > toIndex) {
    455             throw new IndexOutOfBoundsException("fromIndex " + fromIndex
    456                     + " > toIndex " + toIndex);
    457         }
    458 
    459         System.arraycopy(a, toIndex, a, fromIndex, s - toIndex);
    460         int rangeSize = toIndex - fromIndex;
    461         Arrays.fill(a, s - rangeSize, s, null);
    462         size = s - rangeSize;
    463         modCount++;
    464     }
    465 
    466     /**
    467      * Replaces the element at the specified location in this {@code ArrayList}
    468      * with the specified object.
    469      *
    470      * @param index
    471      *            the index at which to put the specified object.
    472      * @param object
    473      *            the object to add.
    474      * @return the previous element at the index.
    475      * @throws IndexOutOfBoundsException
    476      *             when {@code location < 0 || location >= size()}
    477      */
    478     @Override public E set(int index, E object) {
    479         Object[] a = array;
    480         if (index >= size) {
    481             throwIndexOutOfBoundsException(index, size);
    482         }
    483         @SuppressWarnings("unchecked") E result = (E) a[index];
    484         a[index] = object;
    485         return result;
    486     }
    487 
    488     /**
    489      * Returns a new array containing all elements contained in this
    490      * {@code ArrayList}.
    491      *
    492      * @return an array of the elements from this {@code ArrayList}
    493      */
    494     @Override public Object[] toArray() {
    495         int s = size;
    496         Object[] result = new Object[s];
    497         System.arraycopy(array, 0, result, 0, s);
    498         return result;
    499     }
    500 
    501     /**
    502      * Returns an array containing all elements contained in this
    503      * {@code ArrayList}. If the specified array is large enough to hold the
    504      * elements, the specified array is used, otherwise an array of the same
    505      * type is created. If the specified array is used and is larger than this
    506      * {@code ArrayList}, the array element following the collection elements
    507      * is set to null.
    508      *
    509      * @param contents
    510      *            the array.
    511      * @return an array of the elements from this {@code ArrayList}.
    512      * @throws ArrayStoreException
    513      *             when the type of an element in this {@code ArrayList} cannot
    514      *             be stored in the type of the specified array.
    515      */
    516     @Override public <T> T[] toArray(T[] contents) {
    517         int s = size;
    518         if (contents.length < s) {
    519             @SuppressWarnings("unchecked") T[] newArray
    520                 = (T[]) Array.newInstance(contents.getClass().getComponentType(), s);
    521             contents = newArray;
    522         }
    523         System.arraycopy(this.array, 0, contents, 0, s);
    524         if (contents.length > s) {
    525             contents[s] = null;
    526         }
    527         return contents;
    528     }
    529 
    530     /**
    531      * Sets the capacity of this {@code ArrayList} to be the same as the current
    532      * size.
    533      *
    534      * @see #size
    535      */
    536     public void trimToSize() {
    537         int s = size;
    538         if (s == array.length) {
    539             return;
    540         }
    541         if (s == 0) {
    542             array = EmptyArray.OBJECT;
    543         } else {
    544             Object[] newArray = new Object[s];
    545             System.arraycopy(array, 0, newArray, 0, s);
    546             array = newArray;
    547         }
    548         modCount++;
    549     }
    550 
    551     @Override public Iterator<E> iterator() {
    552         return new ArrayListIterator();
    553     }
    554 
    555     private class ArrayListIterator implements Iterator<E> {
    556         /** Number of elements remaining in this iteration */
    557         private int remaining = size;
    558 
    559         /** Index of element that remove() would remove, or -1 if no such elt */
    560         private int removalIndex = -1;
    561 
    562         /** The expected modCount value */
    563         private int expectedModCount = modCount;
    564 
    565         public boolean hasNext() {
    566             return remaining != 0;
    567         }
    568 
    569         @SuppressWarnings("unchecked") public E next() {
    570             ArrayList<E> ourList = ArrayList.this;
    571             int rem = remaining;
    572             if (ourList.modCount != expectedModCount) {
    573                 throw new ConcurrentModificationException();
    574             }
    575             if (rem == 0) {
    576                 throw new NoSuchElementException();
    577             }
    578             remaining = rem - 1;
    579             return (E) ourList.array[removalIndex = ourList.size - rem];
    580         }
    581 
    582         public void remove() {
    583             Object[] a = array;
    584             int removalIdx = removalIndex;
    585             if (modCount != expectedModCount) {
    586                 throw new ConcurrentModificationException();
    587             }
    588             if (removalIdx < 0) {
    589                 throw new IllegalStateException();
    590             }
    591             System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
    592             a[--size] = null;  // Prevent memory leak
    593             removalIndex = -1;
    594             expectedModCount = ++modCount;
    595         }
    596     }
    597 
    598     @Override public int hashCode() {
    599         Object[] a = array;
    600         int hashCode = 1;
    601         for (int i = 0, s = size; i < s; i++) {
    602             Object e = a[i];
    603             hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
    604         }
    605         return hashCode;
    606     }
    607 
    608     @Override public boolean equals(Object o) {
    609         if (o == this) {
    610             return true;
    611         }
    612         if (!(o instanceof List)) {
    613             return false;
    614         }
    615         List<?> that = (List<?>) o;
    616         int s = size;
    617         if (that.size() != s) {
    618             return false;
    619         }
    620         Object[] a = array;
    621         if (that instanceof RandomAccess) {
    622             for (int i = 0; i < s; i++) {
    623                 Object eThis = a[i];
    624                 Object ethat = that.get(i);
    625                 if (eThis == null ? ethat != null : !eThis.equals(ethat)) {
    626                     return false;
    627                 }
    628             }
    629         } else {  // Argument list is not random access; use its iterator
    630             Iterator<?> it = that.iterator();
    631             for (int i = 0; i < s; i++) {
    632                 Object eThis = a[i];
    633                 Object eThat = it.next();
    634                 if (eThis == null ? eThat != null : !eThis.equals(eThat)) {
    635                     return false;
    636                 }
    637             }
    638         }
    639         return true;
    640     }
    641 
    642     private static final long serialVersionUID = 8683452581122892189L;
    643 
    644     private void writeObject(ObjectOutputStream stream) throws IOException {
    645         stream.defaultWriteObject();
    646         stream.writeInt(array.length);
    647         for (int i = 0; i < size; i++) {
    648             stream.writeObject(array[i]);
    649         }
    650     }
    651 
    652     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
    653         stream.defaultReadObject();
    654         int cap = stream.readInt();
    655         if (cap < size) {
    656             throw new InvalidObjectException(
    657                     "Capacity: " + cap + " < size: " + size);
    658         }
    659         array = (cap == 0 ? EmptyArray.OBJECT : new Object[cap]);
    660         for (int i = 0; i < size; i++) {
    661             array[i] = stream.readObject();
    662         }
    663     }
    664  }
    665