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("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 */ 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 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 */ add(E object)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 */ add(int index, E object)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 */ newCapacity(int currentCapacity)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 */ addAll(Collection<? extends E> collection)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 addAll(int index, Collection<? extends E> collection)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 */ throwIndexOutOfBoundsException(int index, int size)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 */ clear()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 */ clone()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 */ ensureCapacity(int minimumCapacity)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 get(int index)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 */ size()318 @Override public int size() { 319 return size; 320 } 321 isEmpty()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 */ contains(Object object)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 indexOf(Object object)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 lastIndexOf(Object object)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 */ remove(int index)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 remove(Object object)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 removeRange(int fromIndex, int toIndex)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 */ set(int index, E object)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 */ toArray()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 */ toArray(T[] contents)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 */ trimToSize()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 iterator()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 hasNext()565 public boolean hasNext() { 566 return remaining != 0; 567 } 568 next()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 remove()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 hashCode()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 equals(Object o)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 writeObject(ObjectOutputStream stream)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 readObject(ObjectInputStream stream)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