• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
ArrayList(int capacity)71     public ArrayList(int capacity) {
72         if (capacity < 0) {
73             throw new IllegalArgumentException();
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      */
ArrayList()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      */
ArrayList(Collection<? extends E> collection)92     public ArrayList(Collection<? extends E> collection) {
93         Object[] a = collection.toArray();
94         if (a.getClass() != Object[].class) {
95             Object[] newArray = new Object[a.length];
96             System.arraycopy(a, 0, newArray, 0, a.length);
97             a = newArray;
98         }
99         array = a;
100         size = a.length;
101     }
102 
103     /**
104      * Adds the specified object at the end of this {@code ArrayList}.
105      *
106      * @param object
107      *            the object to add.
108      * @return always true
109      */
add(E object)110     @Override public boolean add(E object) {
111         Object[] a = array;
112         int s = size;
113         if (s == a.length) {
114             Object[] newArray = new Object[s +
115                     (s < (MIN_CAPACITY_INCREMENT / 2) ?
116                      MIN_CAPACITY_INCREMENT : s >> 1)];
117             System.arraycopy(a, 0, newArray, 0, s);
118             array = a = newArray;
119         }
120         a[s] = object;
121         size = s + 1;
122         modCount++;
123         return true;
124     }
125 
126     /**
127      * Inserts the specified object into this {@code ArrayList} at the specified
128      * location. The object is inserted before any previous element at the
129      * specified location. If the location is equal to the size of this
130      * {@code ArrayList}, the object is added at the end.
131      *
132      * @param index
133      *            the index at which to insert the object.
134      * @param object
135      *            the object to add.
136      * @throws IndexOutOfBoundsException
137      *             when {@code location < 0 || location > size()}
138      */
add(int index, E object)139     @Override public void add(int index, E object) {
140         Object[] a = array;
141         int s = size;
142         if (index > s || index < 0) {
143             throwIndexOutOfBoundsException(index, s);
144         }
145 
146         if (s < a.length) {
147             System.arraycopy(a, index, a, index + 1, s - index);
148         } else {
149             // assert s == a.length;
150             Object[] newArray = new Object[newCapacity(s)];
151             System.arraycopy(a, 0, newArray, 0, index);
152             System.arraycopy(a, index, newArray, index + 1, s - index);
153             array = a = newArray;
154         }
155         a[index] = object;
156         size = s + 1;
157         modCount++;
158     }
159 
160     /**
161      * This method controls the growth of ArrayList capacities.  It represents
162      * a time-space tradeoff: we don't want to grow lists too frequently
163      * (which wastes time and fragments storage), but we don't want to waste
164      * too much space in unused excess capacity.
165      *
166      * NOTE: This method is inlined into {@link #add(Object)} for performance.
167      * If you change the method, change it there too!
168      */
newCapacity(int currentCapacity)169     private static int newCapacity(int currentCapacity) {
170         int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
171                 MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
172         return currentCapacity + increment;
173     }
174 
175     /**
176      * Adds the objects in the specified collection to this {@code ArrayList}.
177      *
178      * @param collection
179      *            the collection of objects.
180      * @return {@code true} if this {@code ArrayList} is modified, {@code false}
181      *         otherwise.
182      */
addAll(Collection<? extends E> collection)183     @Override public boolean addAll(Collection<? extends E> collection) {
184         Object[] newPart = collection.toArray();
185         int newPartSize = newPart.length;
186         if (newPartSize == 0) {
187             return false;
188         }
189         Object[] a = array;
190         int s = size;
191         int newSize = s + newPartSize; // If add overflows, arraycopy will fail
192         if (newSize > a.length) {
193             int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
194             Object[] newArray = new Object[newCapacity];
195             System.arraycopy(a, 0, newArray, 0, s);
196             array = a = newArray;
197         }
198         System.arraycopy(newPart, 0, a, s, newPartSize);
199         size = newSize;
200         modCount++;
201         return true;
202     }
203 
204     /**
205      * Inserts the objects in the specified collection at the specified location
206      * in this List. The objects are added in the order they are returned from
207      * the collection's iterator.
208      *
209      * @param index
210      *            the index at which to insert.
211      * @param collection
212      *            the collection of objects.
213      * @return {@code true} if this {@code ArrayList} is modified, {@code false}
214      *         otherwise.
215      * @throws IndexOutOfBoundsException
216      *             when {@code location < 0 || location > size()}
217      */
218     @Override
addAll(int index, Collection<? extends E> collection)219     public boolean addAll(int index, Collection<? extends E> collection) {
220         int s = size;
221         if (index > s || index < 0) {
222             throwIndexOutOfBoundsException(index, s);
223         }
224         Object[] newPart = collection.toArray();
225         int newPartSize = newPart.length;
226         if (newPartSize == 0) {
227             return false;
228         }
229         Object[] a = array;
230         int newSize = s + newPartSize; // If add overflows, arraycopy will fail
231         if (newSize <= a.length) {
232              System.arraycopy(a, index, a, index + newPartSize, s - index);
233         } else {
234             int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
235             Object[] newArray = new Object[newCapacity];
236             System.arraycopy(a, 0, newArray, 0, index);
237             System.arraycopy(a, index, newArray, index + newPartSize, s-index);
238             array = a = newArray;
239         }
240         System.arraycopy(newPart, 0, a, index, newPartSize);
241         size = newSize;
242         modCount++;
243         return true;
244     }
245 
246     /**
247      * This method was extracted to encourage VM to inline callers.
248      * TODO: when we have a VM that can actually inline, move the test in here too!
249      */
throwIndexOutOfBoundsException(int index, int size)250     static IndexOutOfBoundsException throwIndexOutOfBoundsException(int index, int size) {
251         throw new IndexOutOfBoundsException("Invalid index " + index + ", size is " + size);
252     }
253 
254     /**
255      * Removes all elements from this {@code ArrayList}, leaving it empty.
256      *
257      * @see #isEmpty
258      * @see #size
259      */
clear()260     @Override public void clear() {
261         if (size != 0) {
262             Arrays.fill(array, 0, size, null);
263             size = 0;
264             modCount++;
265         }
266     }
267 
268     /**
269      * Returns a new {@code ArrayList} with the same elements, the same size and
270      * the same capacity as this {@code ArrayList}.
271      *
272      * @return a shallow copy of this {@code ArrayList}
273      * @see java.lang.Cloneable
274      */
clone()275     @Override public Object clone() {
276         try {
277             ArrayList<?> result = (ArrayList<?>) super.clone();
278             result.array = array.clone();
279             return result;
280         } catch (CloneNotSupportedException e) {
281            throw new AssertionError();
282         }
283     }
284 
285     /**
286      * Ensures that after this operation the {@code ArrayList} can hold the
287      * specified number of elements without further growing.
288      *
289      * @param minimumCapacity
290      *            the minimum capacity asked for.
291      */
ensureCapacity(int minimumCapacity)292     public void ensureCapacity(int minimumCapacity) {
293         Object[] a = array;
294         if (a.length < minimumCapacity) {
295             Object[] newArray = new Object[minimumCapacity];
296             System.arraycopy(a, 0, newArray, 0, size);
297             array = newArray;
298             modCount++;
299         }
300     }
301 
get(int index)302     @SuppressWarnings("unchecked") @Override public E get(int index) {
303         if (index >= size) {
304             throwIndexOutOfBoundsException(index, size);
305         }
306         return (E) array[index];
307     }
308 
309     /**
310      * Returns the number of elements in this {@code ArrayList}.
311      *
312      * @return the number of elements in this {@code ArrayList}.
313      */
size()314     @Override public int size() {
315         return size;
316     }
317 
isEmpty()318     @Override public boolean isEmpty() {
319         return size == 0;
320     }
321 
322     /**
323      * Searches this {@code ArrayList} for the specified object.
324      *
325      * @param object
326      *            the object to search for.
327      * @return {@code true} if {@code object} is an element of this
328      *         {@code ArrayList}, {@code false} otherwise
329      */
contains(Object object)330     @Override public boolean contains(Object object) {
331         Object[] a = array;
332         int s = size;
333         if (object != null) {
334             for (int i = 0; i < s; i++) {
335                 if (object.equals(a[i])) {
336                     return true;
337                 }
338             }
339         } else {
340             for (int i = 0; i < s; i++) {
341                 if (a[i] == null) {
342                     return true;
343                 }
344             }
345         }
346         return false;
347     }
348 
indexOf(Object object)349     @Override public int indexOf(Object object) {
350         Object[] a = array;
351         int s = size;
352         if (object != null) {
353             for (int i = 0; i < s; i++) {
354                 if (object.equals(a[i])) {
355                     return i;
356                 }
357             }
358         } else {
359             for (int i = 0; i < s; i++) {
360                 if (a[i] == null) {
361                     return i;
362                 }
363             }
364         }
365         return -1;
366     }
367 
lastIndexOf(Object object)368     @Override public int lastIndexOf(Object object) {
369         Object[] a = array;
370         if (object != null) {
371             for (int i = size - 1; i >= 0; i--) {
372                 if (object.equals(a[i])) {
373                     return i;
374                 }
375             }
376         } else {
377             for (int i = size - 1; i >= 0; i--) {
378                 if (a[i] == null) {
379                     return i;
380                 }
381             }
382         }
383         return -1;
384     }
385 
386     /**
387      * Removes the object at the specified location from this list.
388      *
389      * @param index
390      *            the index of the object to remove.
391      * @return the removed object.
392      * @throws IndexOutOfBoundsException
393      *             when {@code location < 0 || location >= size()}
394      */
remove(int index)395     @Override public E remove(int index) {
396         Object[] a = array;
397         int s = size;
398         if (index >= s) {
399             throwIndexOutOfBoundsException(index, s);
400         }
401         @SuppressWarnings("unchecked") E result = (E) a[index];
402         System.arraycopy(a, index + 1, a, index, --s - index);
403         a[s] = null;  // Prevent memory leak
404         size = s;
405         modCount++;
406         return result;
407     }
408 
remove(Object object)409     @Override public boolean remove(Object object) {
410         Object[] a = array;
411         int s = size;
412         if (object != null) {
413             for (int i = 0; i < s; i++) {
414                 if (object.equals(a[i])) {
415                     System.arraycopy(a, i + 1, a, i, --s - i);
416                     a[s] = null;  // Prevent memory leak
417                     size = s;
418                     modCount++;
419                     return true;
420                 }
421             }
422         } else {
423             for (int i = 0; i < s; i++) {
424                 if (a[i] == null) {
425                     System.arraycopy(a, i + 1, a, i, --s - i);
426                     a[s] = null;  // Prevent memory leak
427                     size = s;
428                     modCount++;
429                     return true;
430                 }
431             }
432         }
433         return false;
434     }
435 
removeRange(int fromIndex, int toIndex)436     @Override protected void removeRange(int fromIndex, int toIndex) {
437         if (fromIndex == toIndex) {
438             return;
439         }
440         Object[] a = array;
441         int s = size;
442         if (fromIndex >= s) {
443             throw new IndexOutOfBoundsException("fromIndex " + fromIndex
444                     + " >= size " + size);
445         }
446         if (toIndex > s) {
447             throw new IndexOutOfBoundsException("toIndex " + toIndex
448                     + " > size " + size);
449         }
450         if (fromIndex > toIndex) {
451             throw new IndexOutOfBoundsException("fromIndex " + fromIndex
452                     + " > toIndex " + toIndex);
453         }
454 
455         System.arraycopy(a, toIndex, a, fromIndex, s - toIndex);
456         int rangeSize = toIndex - fromIndex;
457         Arrays.fill(a, s - rangeSize, s, null);
458         size = s - rangeSize;
459         modCount++;
460     }
461 
462     /**
463      * Replaces the element at the specified location in this {@code ArrayList}
464      * with the specified object.
465      *
466      * @param index
467      *            the index at which to put the specified object.
468      * @param object
469      *            the object to add.
470      * @return the previous element at the index.
471      * @throws IndexOutOfBoundsException
472      *             when {@code location < 0 || location >= size()}
473      */
set(int index, E object)474     @Override public E set(int index, E object) {
475         Object[] a = array;
476         if (index >= size) {
477             throwIndexOutOfBoundsException(index, size);
478         }
479         @SuppressWarnings("unchecked") E result = (E) a[index];
480         a[index] = object;
481         return result;
482     }
483 
484     /**
485      * Returns a new array containing all elements contained in this
486      * {@code ArrayList}.
487      *
488      * @return an array of the elements from this {@code ArrayList}
489      */
toArray()490     @Override public Object[] toArray() {
491         int s = size;
492         Object[] result = new Object[s];
493         System.arraycopy(array, 0, result, 0, s);
494         return result;
495     }
496 
497     /**
498      * Returns an array containing all elements contained in this
499      * {@code ArrayList}. If the specified array is large enough to hold the
500      * elements, the specified array is used, otherwise an array of the same
501      * type is created. If the specified array is used and is larger than this
502      * {@code ArrayList}, the array element following the collection elements
503      * is set to null.
504      *
505      * @param contents
506      *            the array.
507      * @return an array of the elements from this {@code ArrayList}.
508      * @throws ArrayStoreException
509      *             when the type of an element in this {@code ArrayList} cannot
510      *             be stored in the type of the specified array.
511      */
toArray(T[] contents)512     @Override public <T> T[] toArray(T[] contents) {
513         int s = size;
514         if (contents.length < s) {
515             @SuppressWarnings("unchecked") T[] newArray
516                 = (T[]) Array.newInstance(contents.getClass().getComponentType(), s);
517             contents = newArray;
518         }
519         System.arraycopy(this.array, 0, contents, 0, s);
520         if (contents.length > s) {
521             contents[s] = null;
522         }
523         return contents;
524     }
525 
526     /**
527      * Sets the capacity of this {@code ArrayList} to be the same as the current
528      * size.
529      *
530      * @see #size
531      */
trimToSize()532     public void trimToSize() {
533         int s = size;
534         if (s == array.length) {
535             return;
536         }
537         if (s == 0) {
538             array = EmptyArray.OBJECT;
539         } else {
540             Object[] newArray = new Object[s];
541             System.arraycopy(array, 0, newArray, 0, s);
542             array = newArray;
543         }
544         modCount++;
545     }
546 
iterator()547     @Override public Iterator<E> iterator() {
548         return new ArrayListIterator();
549     }
550 
551     private class ArrayListIterator implements Iterator<E> {
552         /** Number of elements remaining in this iteration */
553         private int remaining = size;
554 
555         /** Index of element that remove() would remove, or -1 if no such elt */
556         private int removalIndex = -1;
557 
558         /** The expected modCount value */
559         private int expectedModCount = modCount;
560 
hasNext()561         public boolean hasNext() {
562             return remaining != 0;
563         }
564 
next()565         @SuppressWarnings("unchecked") public E next() {
566             ArrayList<E> ourList = ArrayList.this;
567             int rem = remaining;
568             if (ourList.modCount != expectedModCount) {
569                 throw new ConcurrentModificationException();
570             }
571             if (rem == 0) {
572                 throw new NoSuchElementException();
573             }
574             remaining = rem - 1;
575             return (E) ourList.array[removalIndex = ourList.size - rem];
576         }
577 
remove()578         public void remove() {
579             Object[] a = array;
580             int removalIdx = removalIndex;
581             if (modCount != expectedModCount) {
582                 throw new ConcurrentModificationException();
583             }
584             if (removalIdx < 0) {
585                 throw new IllegalStateException();
586             }
587             System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
588             a[--size] = null;  // Prevent memory leak
589             removalIndex = -1;
590             expectedModCount = ++modCount;
591         }
592     }
593 
hashCode()594     @Override public int hashCode() {
595         Object[] a = array;
596         int hashCode = 1;
597         for (int i = 0, s = size; i < s; i++) {
598             Object e = a[i];
599             hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
600         }
601         return hashCode;
602     }
603 
equals(Object o)604     @Override public boolean equals(Object o) {
605         if (o == this) {
606             return true;
607         }
608         if (!(o instanceof List)) {
609             return false;
610         }
611         List<?> that = (List<?>) o;
612         int s = size;
613         if (that.size() != s) {
614             return false;
615         }
616         Object[] a = array;
617         if (that instanceof RandomAccess) {
618             for (int i = 0; i < s; i++) {
619                 Object eThis = a[i];
620                 Object ethat = that.get(i);
621                 if (eThis == null ? ethat != null : !eThis.equals(ethat)) {
622                     return false;
623                 }
624             }
625         } else {  // Argument list is not random access; use its iterator
626             Iterator<?> it = that.iterator();
627             for (int i = 0; i < s; i++) {
628                 Object eThis = a[i];
629                 Object eThat = it.next();
630                 if (eThis == null ? eThat != null : !eThis.equals(eThat)) {
631                     return false;
632                 }
633             }
634         }
635         return true;
636     }
637 
638     private static final long serialVersionUID = 8683452581122892189L;
639 
writeObject(ObjectOutputStream stream)640     private void writeObject(ObjectOutputStream stream) throws IOException {
641         stream.defaultWriteObject();
642         stream.writeInt(array.length);
643         for (int i = 0; i < size; i++) {
644             stream.writeObject(array[i]);
645         }
646     }
647 
readObject(ObjectInputStream stream)648     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
649         stream.defaultReadObject();
650         int cap = stream.readInt();
651         if (cap < size) {
652             throw new InvalidObjectException(
653                     "Capacity: " + cap + " < size: " + size);
654         }
655         array = (cap == 0 ? EmptyArray.OBJECT : new Object[cap]);
656         for (int i = 0; i < size; i++) {
657             array[i] = stream.readObject();
658         }
659     }
660  }
661