AbstractList.java revision fdb2704414a9ed92394ada0d1395e4db86889465
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 18package java.util; 19 20/** 21 * AbstractList is an abstract implementation of the List interface, optimized 22 * for a backing store which supports random access. This implementation does 23 * not support adding or replacing. A subclass must implement the abstract 24 * methods get() and size(). 25 * 26 * @since 1.2 27 */ 28public abstract class AbstractList<E> extends AbstractCollection<E> implements 29 List<E> { 30 31 protected transient int modCount; 32 33 private class SimpleListIterator implements Iterator<E> { 34 int pos = -1; 35 36 int expectedModCount; 37 38 int lastPosition = -1; 39 40 SimpleListIterator() { 41 super(); 42 expectedModCount = modCount; 43 } 44 45 public boolean hasNext() { 46 return pos + 1 < size(); 47 } 48 49 public E next() { 50 if (expectedModCount == modCount) { 51 try { 52 E result = get(pos + 1); 53 lastPosition = ++pos; 54 return result; 55 } catch (IndexOutOfBoundsException e) { 56 throw new NoSuchElementException(); 57 } 58 } 59 throw new ConcurrentModificationException(); 60 } 61 62 public void remove() { 63 if (expectedModCount == modCount) { 64 try { 65 AbstractList.this.remove(lastPosition); 66 } catch (IndexOutOfBoundsException e) { 67 throw new IllegalStateException(); 68 } 69 if (modCount != expectedModCount) { 70 expectedModCount++; 71 } 72 if (pos == lastPosition) { 73 pos--; 74 } 75 lastPosition = -1; 76 } else { 77 throw new ConcurrentModificationException(); 78 } 79 } 80 } 81 82 private final class FullListIterator extends SimpleListIterator implements 83 ListIterator<E> { 84 FullListIterator(int start) { 85 super(); 86 if (0 <= start && start <= size()) { 87 pos = start - 1; 88 } else { 89 throw new IndexOutOfBoundsException(); 90 } 91 } 92 93 public void add(E object) { 94 if (expectedModCount == modCount) { 95 try { 96 AbstractList.this.add(pos + 1, object); 97 } catch (IndexOutOfBoundsException e) { 98 throw new NoSuchElementException(); 99 } 100 pos++; 101 lastPosition = -1; 102 if (modCount != expectedModCount) { 103 expectedModCount++; 104 } 105 } else { 106 throw new ConcurrentModificationException(); 107 } 108 } 109 110 public boolean hasPrevious() { 111 return pos >= 0; 112 } 113 114 public int nextIndex() { 115 return pos + 1; 116 } 117 118 public E previous() { 119 if (expectedModCount == modCount) { 120 try { 121 E result = get(pos); 122 lastPosition = pos; 123 pos--; 124 return result; 125 } catch (IndexOutOfBoundsException e) { 126 throw new NoSuchElementException(); 127 } 128 } 129 throw new ConcurrentModificationException(); 130 } 131 132 public int previousIndex() { 133 return pos; 134 } 135 136 public void set(E object) { 137 if (expectedModCount == modCount) { 138 try { 139 AbstractList.this.set(lastPosition, object); 140 } catch (IndexOutOfBoundsException e) { 141 throw new IllegalStateException(); 142 } 143 } else { 144 throw new ConcurrentModificationException(); 145 } 146 } 147 } 148 149 private static final class SubAbstractListRandomAccess<E> extends 150 SubAbstractList<E> implements RandomAccess { 151 SubAbstractListRandomAccess(AbstractList<E> list, int start, int end) { 152 super(list, start, end); 153 } 154 } 155 156 private static class SubAbstractList<E> extends AbstractList<E> { 157 private final AbstractList<E> fullList; 158 159 private int offset; 160 161 private int size; 162 163 private static final class SubAbstractListIterator<E> implements 164 ListIterator<E> { 165 private final SubAbstractList<E> subList; 166 167 private final ListIterator<E> iterator; 168 169 private int start; 170 171 private int end; 172 173 SubAbstractListIterator(ListIterator<E> it, 174 SubAbstractList<E> list, int offset, int length) { 175 super(); 176 iterator = it; 177 subList = list; 178 start = offset; 179 end = start + length; 180 } 181 182 public void add(E object) { 183 iterator.add(object); 184 subList.sizeChanged(true); 185 end++; 186 } 187 188 public boolean hasNext() { 189 return iterator.nextIndex() < end; 190 } 191 192 public boolean hasPrevious() { 193 return iterator.previousIndex() >= start; 194 } 195 196 public E next() { 197 if (iterator.nextIndex() < end) { 198 return iterator.next(); 199 } 200 throw new NoSuchElementException(); 201 } 202 203 public int nextIndex() { 204 return iterator.nextIndex() - start; 205 } 206 207 public E previous() { 208 if (iterator.previousIndex() >= start) { 209 return iterator.previous(); 210 } 211 throw new NoSuchElementException(); 212 } 213 214 public int previousIndex() { 215 int previous = iterator.previousIndex(); 216 if (previous >= start) { 217 return previous - start; 218 } 219 return -1; 220 } 221 222 public void remove() { 223 iterator.remove(); 224 subList.sizeChanged(false); 225 end--; 226 } 227 228 public void set(E object) { 229 iterator.set(object); 230 } 231 } 232 233 SubAbstractList(AbstractList<E> list, int start, int end) { 234 super(); 235 fullList = list; 236 modCount = fullList.modCount; 237 offset = start; 238 size = end - start; 239 } 240 241 @Override 242 public void add(int location, E object) { 243 if (modCount == fullList.modCount) { 244 if (0 <= location && location <= size) { 245 fullList.add(location + offset, object); 246 size++; 247 modCount = fullList.modCount; 248 } else { 249 throw new IndexOutOfBoundsException(); 250 } 251 } else { 252 throw new ConcurrentModificationException(); 253 } 254 } 255 256 @Override 257 public boolean addAll(int location, Collection<? extends E> collection) { 258 if (modCount == fullList.modCount) { 259 if (0 <= location && location <= size) { 260 boolean result = fullList.addAll(location + offset, 261 collection); 262 if (result) { 263 size += collection.size(); 264 modCount = fullList.modCount; 265 } 266 return result; 267 } 268 throw new IndexOutOfBoundsException(); 269 } 270 throw new ConcurrentModificationException(); 271 } 272 273 @Override 274 public boolean addAll(Collection<? extends E> collection) { 275 if (modCount == fullList.modCount) { 276 boolean result = fullList.addAll(offset + size, collection); 277 if (result) { 278 size += collection.size(); 279 modCount = fullList.modCount; 280 } 281 return result; 282 } 283 throw new ConcurrentModificationException(); 284 } 285 286 @Override 287 public E get(int location) { 288 if (modCount == fullList.modCount) { 289 if (0 <= location && location < size) { 290 return fullList.get(location + offset); 291 } 292 throw new IndexOutOfBoundsException(); 293 } 294 throw new ConcurrentModificationException(); 295 } 296 297 @Override 298 public Iterator<E> iterator() { 299 return listIterator(0); 300 } 301 302 @Override 303 public ListIterator<E> listIterator(int location) { 304 if (modCount == fullList.modCount) { 305 if (0 <= location && location <= size) { 306 return new SubAbstractListIterator<E>(fullList 307 .listIterator(location + offset), this, offset, 308 size); 309 } 310 throw new IndexOutOfBoundsException(); 311 } 312 throw new ConcurrentModificationException(); 313 } 314 315 @Override 316 public E remove(int location) { 317 if (modCount == fullList.modCount) { 318 if (0 <= location && location < size) { 319 E result = fullList.remove(location + offset); 320 size--; 321 modCount = fullList.modCount; 322 return result; 323 } 324 throw new IndexOutOfBoundsException(); 325 } 326 throw new ConcurrentModificationException(); 327 } 328 329 @Override 330 protected void removeRange(int start, int end) { 331 if (start != end) { 332 if (modCount == fullList.modCount) { 333 fullList.removeRange(start + offset, end + offset); 334 size -= end - start; 335 modCount = fullList.modCount; 336 } else { 337 throw new ConcurrentModificationException(); 338 } 339 } 340 } 341 342 @Override 343 public E set(int location, E object) { 344 if (modCount == fullList.modCount) { 345 if (0 <= location && location < size) { 346 return fullList.set(location + offset, object); 347 } 348 throw new IndexOutOfBoundsException(); 349 } 350 throw new ConcurrentModificationException(); 351 } 352 353 @Override 354 public int size() { 355 return size; 356 } 357 358 void sizeChanged(boolean increment) { 359 if (increment) { 360 size++; 361 } else { 362 size--; 363 } 364 modCount = fullList.modCount; 365 } 366 } 367 368 /** 369 * Constructs a new instance of this AbstractList. 370 * 371 */ 372 protected AbstractList() { 373 super(); 374 } 375 376 /** 377 * Inserts the specified object into this List at the specified location. 378 * The object is inserted before any previous element at the specified 379 * location. If the location is equal to the size of this List, the object 380 * is added at the end. 381 * 382 * 383 * @param location 384 * the index at which to insert 385 * @param object 386 * the object to add 387 * 388 * @exception UnsupportedOperationException 389 * when adding to this List is not supported 390 * @exception ClassCastException 391 * when the class of the object is inappropriate for this 392 * List 393 * @exception IllegalArgumentException 394 * when the object cannot be added to this List 395 * @exception IndexOutOfBoundsException 396 * when <code>location < 0 || >= size()</code> 397 */ 398 public void add(int location, E object) { 399 throw new UnsupportedOperationException(); 400 } 401 402 /** 403 * Adds the specified object at the end of this List. 404 * 405 * 406 * @param object 407 * the object to add 408 * @return true 409 * 410 * @exception UnsupportedOperationException 411 * when adding to this List is not supported 412 * @exception ClassCastException 413 * when the class of the object is inappropriate for this 414 * List 415 * @exception IllegalArgumentException 416 * when the object cannot be added to this List 417 */ 418 @Override 419 public boolean add(E object) { 420 add(size(), object); 421 return true; 422 } 423 424 /** 425 * Inserts the objects in the specified Collection at the specified location 426 * in this List. The objects are added in the order they are returned from 427 * the Collection iterator. 428 * 429 * 430 * @param location 431 * the index at which to insert 432 * @param collection 433 * the Collection of objects 434 * @return true if this List is modified, false otherwise 435 * 436 * @exception UnsupportedOperationException 437 * when adding to this List is not supported 438 * @exception ClassCastException 439 * when the class of an object is inappropriate for this List 440 * @exception IllegalArgumentException 441 * when an object cannot be added to this List 442 * @exception IndexOutOfBoundsException 443 * when <code>location < 0 || >= size()</code> 444 */ 445 public boolean addAll(int location, Collection<? extends E> collection) { 446 Iterator<? extends E> it = collection.iterator(); 447 while (it.hasNext()) { 448 add(location++, it.next()); 449 } 450 return !collection.isEmpty(); 451 } 452 453 /** 454 * Removes all elements from this List, leaving it empty. 455 * 456 * 457 * @exception UnsupportedOperationException 458 * when removing from this List is not supported 459 * 460 * @see List#isEmpty 461 * @see List#size 462 */ 463 @Override 464 public void clear() { 465 removeRange(0, size()); 466 } 467 468 /** 469 * Compares the specified object to this List and answer if they are equal. 470 * The object must be a List which contains the same objects in the same 471 * order. 472 * 473 * 474 * @param object 475 * the object to compare with this object 476 * @return true if the specified object is equal to this List, false 477 * otherwise 478 * 479 * @see #hashCode 480 */ 481 @Override 482 public boolean equals(Object object) { 483 if (this == object) { 484 return true; 485 } 486 if (object instanceof List) { 487 List<?> list = (List<?>) object; 488 if (list.size() != size()) { 489 return false; 490 } 491 492 Iterator<?> it1 = iterator(), it2 = list.iterator(); 493 while (it1.hasNext()) { 494 Object e1 = it1.next(), e2 = it2.next(); 495 if (!(e1 == null ? e2 == null : e1.equals(e2))) { 496 return false; 497 } 498 } 499 return true; 500 } 501 return false; 502 } 503 504 /** 505 * Returns the element at the specified location in this List. 506 * 507 * 508 * @param location 509 * the index of the element to return 510 * @return the element at the specified index 511 * 512 * @exception IndexOutOfBoundsException 513 * when <code>location < 0 || >= size()</code> 514 */ 515 public abstract E get(int location); 516 517 /** 518 * Returns an integer hash code for the receiver. Objects which are equal 519 * answer the same value for this method. 520 * 521 * 522 * @return the receiver's hash 523 * 524 * @see #equals 525 */ 526 @Override 527 public int hashCode() { 528 int result = 1; 529 Iterator<?> it = iterator(); 530 while (it.hasNext()) { 531 Object object = it.next(); 532 result = (31 * result) + (object == null ? 0 : object.hashCode()); 533 } 534 return result; 535 } 536 537 /** 538 * Searches this List for the specified object and returns the index of the 539 * first occurrence. 540 * 541 * 542 * @param object 543 * the object to search for 544 * @return the index of the first occurrence of the object 545 */ 546 public int indexOf(Object object) { 547 ListIterator<?> it = listIterator(); 548 if (object != null) { 549 while (it.hasNext()) { 550 if (object.equals(it.next())) { 551 return it.previousIndex(); 552 } 553 } 554 } else { 555 while (it.hasNext()) { 556 if (it.next() == null) { 557 return it.previousIndex(); 558 } 559 } 560 } 561 return -1; 562 } 563 564 /** 565 * Returns an Iterator on the elements of this List. The elements are 566 * iterated in the same order that they occur in the List. 567 * 568 * 569 * @return an Iterator on the elements of this List 570 * 571 * @see Iterator 572 */ 573 @Override 574 public Iterator<E> iterator() { 575 return new SimpleListIterator(); 576 } 577 578 /** 579 * Searches this List for the specified object and returns the index of the 580 * last occurrence. 581 * 582 * 583 * @param object 584 * the object to search for 585 * @return the index of the last occurrence of the object 586 */ 587 public int lastIndexOf(Object object) { 588 ListIterator<?> it = listIterator(size()); 589 if (object != null) { 590 while (it.hasPrevious()) { 591 if (object.equals(it.previous())) { 592 return it.nextIndex(); 593 } 594 } 595 } else { 596 while (it.hasPrevious()) { 597 if (it.previous() == null) { 598 return it.nextIndex(); 599 } 600 } 601 } 602 return -1; 603 } 604 605 /** 606 * Returns a ListIterator on the elements of this List. The elements are 607 * iterated in the same order that they occur in the List. 608 * 609 * 610 * @return a ListIterator on the elements of this List 611 * 612 * @see ListIterator 613 */ 614 public ListIterator<E> listIterator() { 615 return listIterator(0); 616 } 617 618 /** 619 * Returns a ListIterator on the elements of this List. The elements are 620 * iterated in the same order that they occur in the List. The iteration 621 * starts at the specified location. 622 * 623 * 624 * @param location 625 * the index at which to start the iteration 626 * @return a ListIterator on the elements of this List 627 * 628 * @exception IndexOutOfBoundsException 629 * when <code>location < 0 || >= size()</code> 630 * 631 * @see ListIterator 632 */ 633 public ListIterator<E> listIterator(int location) { 634 return new FullListIterator(location); 635 } 636 637 /** 638 * Removes the object at the specified location from this List. 639 * 640 * 641 * @param location 642 * the index of the object to remove 643 * @return the removed object 644 * 645 * @exception UnsupportedOperationException 646 * when removing from this List is not supported 647 * @exception IndexOutOfBoundsException 648 * when <code>location < 0 || >= size()</code> 649 */ 650 public E remove(int location) { 651 throw new UnsupportedOperationException(); 652 } 653 654 /** 655 * Removes the objects in the specified range from the start to the, but not 656 * including, end index. 657 * 658 * 659 * @param start 660 * the index at which to start removing 661 * @param end 662 * the index one past the end of the range to remove 663 * 664 * @exception UnsupportedOperationException 665 * when removing from this List is not supported 666 * @exception IndexOutOfBoundsException 667 * when <code>start < 0 668 */ 669 protected void removeRange(int start, int end) { 670 Iterator<?> it = listIterator(start); 671 for (int i = start; i < end; i++) { 672 it.next(); 673 it.remove(); 674 } 675 } 676 677 /** 678 * Replaces the element at the specified location in this List with the 679 * specified object. 680 * 681 * 682 * @param location 683 * the index at which to put the specified object 684 * @param object 685 * the object to add 686 * @return the previous element at the index 687 * 688 * @exception UnsupportedOperationException 689 * when replacing elements in this List is not supported 690 * @exception ClassCastException 691 * when the class of an object is inappropriate for this List 692 * @exception IllegalArgumentException 693 * when an object cannot be added to this List 694 * @exception IndexOutOfBoundsException 695 * when <code>location < 0 || >= size()</code> 696 */ 697 public E set(int location, E object) { 698 throw new UnsupportedOperationException(); 699 } 700 701 /** 702 * Returns a part of consecutive elements of this list as a view. From start 703 * (inclusive), to end(exclusive). The returned view will be of zero length 704 * if start equals end. Any change occurs in the returned subList will be 705 * reflected to the original list, and vice-versa. All the supported 706 * optional operations by the original list will also be supported by this 707 * subList. 708 * 709 * This method can be used as a handy method to do some operations on a sub 710 * range of the original list. For example: list.subList(from, to).clear(); 711 * 712 * If the original list is modified other than through the returned subList, 713 * the behavior of the returned subList becomes undefined. 714 * 715 * The returned subList is a subclass of AbstractList. The subclass stores 716 * offset, size of itself, and modCount of the original list. If the 717 * original list implements RandomAccess interface, the returned subList 718 * also implements RandomAccess interface. 719 * 720 * The subList's set(int, Object), get(int), add(int, Object), remove(int), 721 * addAll(int, Collection) and removeRange(int, int) methods first check the 722 * bounds, adjust offsets and then call the corresponding methods of the 723 * original AbstractList. addAll(Collection c) method of the returned 724 * subList calls the original addAll(offset + size, c). 725 * 726 * The listIterator(int) method of the subList wraps the original list 727 * iterator. The iterator() method of the subList invokes the original 728 * listIterator() method, and the size() method merely returns the size of 729 * the subList. 730 * 731 * All methods will throw a ConcurrentModificationException if the modCount 732 * of the original list is not equal to the expected value. 733 * 734 * @param start 735 * start index of the subList, include start 736 * @param end 737 * end index of the subList, exclude end 738 * @return a subList view of this list start from start (inclusive), end 739 * with end (exclusive) 740 * @exception IndexOutOfBoundsException 741 * when (start < 0 || end > size()) 742 * @exception IllegalArgumentException 743 * when (start > end) 744 */ 745 public List<E> subList(int start, int end) { 746 if (0 <= start && end <= size()) { 747 if (start <= end) { 748 if (this instanceof RandomAccess) { 749 return new SubAbstractListRandomAccess<E>(this, start, end); 750 } 751 return new SubAbstractList<E>(this, start, end); 752 } 753 throw new IllegalArgumentException(); 754 } 755 throw new IndexOutOfBoundsException(); 756 } 757} 758