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
20import java.io.IOException;
21import java.io.ObjectOutputStream;
22import java.io.Serializable;
23import java.lang.reflect.Array;
24
25/**
26 * Vector is an implementation of {@link List}, backed by an array and synchronized.
27 * All optional operations including adding, removing, and replacing elements are supported.
28 *
29 * <p>All elements are permitted, including null.
30 *
31 * <p>This class is equivalent to {@link ArrayList} with synchronized operations. This has a
32 * performance cost, and the synchronization is not necessarily meaningful to your application:
33 * synchronizing each call to {@code get}, for example, is not equivalent to synchronizing on the
34 * list and iterating over it (which is probably what you intended). If you do need very highly
35 * concurrent access, you should also consider {@link java.util.concurrent.CopyOnWriteArrayList}.
36 *
37 * @param <E> The element type of this list.
38 */
39public class Vector<E> extends AbstractList<E> implements List<E>,
40        RandomAccess, Cloneable, Serializable {
41
42    private static final long serialVersionUID = -2767605614048989439L;
43
44    /**
45     * The number of elements or the size of the vector.
46     */
47    protected int elementCount;
48
49    /**
50     * The elements of the vector.
51     */
52    protected Object[] elementData;
53
54    /**
55     * How many elements should be added to the vector when it is detected that
56     * it needs to grow to accommodate extra entries. If this value is zero or
57     * negative the size will be doubled if an increase is needed.
58     */
59    protected int capacityIncrement;
60
61    private static final int DEFAULT_SIZE = 10;
62
63    /**
64     * Constructs a new vector using the default capacity.
65     */
66    public Vector() {
67        this(DEFAULT_SIZE, 0);
68    }
69
70    /**
71     * Constructs a new vector using the specified capacity.
72     *
73     * @param capacity
74     *            the initial capacity of the new vector.
75     * @throws IllegalArgumentException
76     *             if {@code capacity} is negative.
77     */
78    public Vector(int capacity) {
79        this(capacity, 0);
80    }
81
82    /**
83     * Constructs a new vector using the specified capacity and capacity
84     * increment.
85     *
86     * @param capacity
87     *            the initial capacity of the new vector.
88     * @param capacityIncrement
89     *            the amount to increase the capacity when this vector is full.
90     * @throws IllegalArgumentException
91     *             if {@code capacity} is negative.
92     */
93    public Vector(int capacity, int capacityIncrement) {
94        if (capacity < 0) {
95            throw new IllegalArgumentException("capacity < 0: " + capacity);
96        }
97        elementData = newElementArray(capacity);
98        elementCount = 0;
99        this.capacityIncrement = capacityIncrement;
100    }
101
102    /**
103     * Constructs a new instance of {@code Vector} containing the elements in
104     * {@code collection}. The order of the elements in the new {@code Vector}
105     * is dependent on the iteration order of the seed collection.
106     *
107     * @param collection
108     *            the collection of elements to add.
109     */
110    public Vector(Collection<? extends E> collection) {
111        this(collection.size(), 0);
112        Iterator<? extends E> it = collection.iterator();
113        while (it.hasNext()) {
114            elementData[elementCount++] = it.next();
115        }
116    }
117
118    @SuppressWarnings("unchecked")
119    private E[] newElementArray(int size) {
120        return (E[]) new Object[size];
121    }
122
123    /**
124     * Adds the specified object into this vector at the specified location. The
125     * object is inserted before any element with the same or a higher index
126     * increasing their index by 1. If the location is equal to the size of this
127     * vector, the object is added at the end.
128     *
129     * @param location
130     *            the index at which to insert the element.
131     * @param object
132     *            the object to insert in this vector.
133     * @throws ArrayIndexOutOfBoundsException
134     *                if {@code location < 0 || location > size()}.
135     * @see #addElement
136     * @see #size
137     */
138    @Override
139    public void add(int location, E object) {
140        insertElementAt(object, location);
141    }
142
143    /**
144     * Adds the specified object at the end of this vector.
145     *
146     * @param object
147     *            the object to add to the vector.
148     * @return {@code true}
149     */
150    @Override
151    public synchronized boolean add(E object) {
152        if (elementCount == elementData.length) {
153            growByOne();
154        }
155        elementData[elementCount++] = object;
156        modCount++;
157        return true;
158    }
159
160    /**
161     * Inserts the objects in the specified collection at the specified location
162     * in this vector. The objects are inserted in the order in which they are
163     * returned from the Collection iterator. The elements with an index equal
164     * or higher than {@code location} have their index increased by the size of
165     * the added collection.
166     *
167     * @param location
168     *            the location to insert the objects.
169     * @param collection
170     *            the collection of objects.
171     * @return {@code true} if this vector is modified, {@code false} otherwise.
172     * @throws ArrayIndexOutOfBoundsException
173     *                if {@code location < 0} or {@code location > size()}.
174     */
175    @Override
176    public synchronized boolean addAll(int location, Collection<? extends E> collection) {
177        if (location >= 0 && location <= elementCount) {
178            int size = collection.size();
179            if (size == 0) {
180                return false;
181            }
182            int required = size - (elementData.length - elementCount);
183            if (required > 0) {
184                growBy(required);
185            }
186            int count = elementCount - location;
187            if (count > 0) {
188                System.arraycopy(elementData, location, elementData, location
189                        + size, count);
190            }
191            Iterator<? extends E> it = collection.iterator();
192            while (it.hasNext()) {
193                elementData[location++] = it.next();
194            }
195            elementCount += size;
196            modCount++;
197            return true;
198        }
199        throw arrayIndexOutOfBoundsException(location, elementCount);
200    }
201
202    /**
203     * Adds the objects in the specified collection to the end of this vector.
204     *
205     * @param collection
206     *            the collection of objects.
207     * @return {@code true} if this vector is modified, {@code false} otherwise.
208     */
209    @Override
210    public synchronized boolean addAll(Collection<? extends E> collection) {
211        return addAll(elementCount, collection);
212    }
213
214    /**
215     * Adds the specified object at the end of this vector.
216     *
217     * @param object
218     *            the object to add to the vector.
219     */
220    public synchronized void addElement(E object) {
221        if (elementCount == elementData.length) {
222            growByOne();
223        }
224        elementData[elementCount++] = object;
225        modCount++;
226    }
227
228    /**
229     * Returns the number of elements this vector can hold without growing.
230     *
231     * @return the capacity of this vector.
232     * @see #ensureCapacity
233     * @see #size
234     */
235    public synchronized int capacity() {
236        return elementData.length;
237    }
238
239    /**
240     * Removes all elements from this vector, leaving it empty.
241     *
242     * @see #isEmpty
243     * @see #size
244     */
245    @Override
246    public void clear() {
247        removeAllElements();
248    }
249
250    /**
251     * Returns a new vector with the same elements, size, capacity and capacity
252     * increment as this vector.
253     *
254     * @return a shallow copy of this vector.
255     * @see java.lang.Cloneable
256     */
257    @Override
258    @SuppressWarnings("unchecked")
259    public synchronized Object clone() {
260        try {
261            Vector<E> vector = (Vector<E>) super.clone();
262            vector.elementData = elementData.clone();
263            return vector;
264        } catch (CloneNotSupportedException e) {
265            throw new AssertionError(e);
266        }
267    }
268
269    /**
270     * Searches this vector for the specified object.
271     *
272     * @param object
273     *            the object to look for in this vector.
274     * @return {@code true} if object is an element of this vector,
275     *         {@code false} otherwise.
276     * @see #indexOf(Object)
277     * @see #indexOf(Object, int)
278     * @see java.lang.Object#equals
279     */
280    @Override
281    public boolean contains(Object object) {
282        return indexOf(object, 0) != -1;
283    }
284
285    /**
286     * Searches this vector for all objects in the specified collection.
287     *
288     * @param collection
289     *            the collection of objects.
290     * @return {@code true} if all objects in the specified collection are
291     *         elements of this vector, {@code false} otherwise.
292     */
293    @Override
294    public synchronized boolean containsAll(Collection<?> collection) {
295        return super.containsAll(collection);
296    }
297
298    /**
299     * Attempts to copy elements contained by this {@code Vector} into the
300     * corresponding elements of the supplied {@code Object} array.
301     *
302     * @param elements
303     *            the {@code Object} array into which the elements of this
304     *            vector are copied.
305     * @throws IndexOutOfBoundsException
306     *             if {@code elements} is not big enough.
307     * @see #clone
308     */
309    public synchronized void copyInto(Object[] elements) {
310        System.arraycopy(elementData, 0, elements, 0, elementCount);
311    }
312
313    /**
314     * Returns the element at the specified location in this vector.
315     *
316     * @param location
317     *            the index of the element to return in this vector.
318     * @return the element at the specified location.
319     * @throws ArrayIndexOutOfBoundsException
320     *                if {@code location < 0 || location >= size()}.
321     * @see #size
322     */
323    @SuppressWarnings("unchecked")
324    public synchronized E elementAt(int location) {
325        if (location < elementCount) {
326            return (E) elementData[location];
327        }
328        throw arrayIndexOutOfBoundsException(location, elementCount);
329    }
330
331    /**
332     * Returns an enumeration on the elements of this vector. The results of the
333     * enumeration may be affected if the contents of this vector is modified.
334     *
335     * @return an enumeration of the elements of this vector.
336     * @see #elementAt
337     * @see Enumeration
338     */
339    public Enumeration<E> elements() {
340        return new Enumeration<E>() {
341            int pos = 0;
342
343            public boolean hasMoreElements() {
344                return pos < elementCount;
345            }
346
347            @SuppressWarnings("unchecked")
348            public E nextElement() {
349                synchronized (Vector.this) {
350                    if (pos < elementCount) {
351                        return (E) elementData[pos++];
352                    }
353                }
354                throw new NoSuchElementException();
355            }
356        };
357    }
358
359    /**
360     * Ensures that this vector can hold the specified number of elements
361     * without growing.
362     *
363     * @param minimumCapacity
364     *            the minimum number of elements that this vector will hold
365     *            before growing.
366     * @see #capacity
367     */
368    public synchronized void ensureCapacity(int minimumCapacity) {
369        if (elementData.length < minimumCapacity) {
370            int next = (capacityIncrement <= 0 ? elementData.length
371                    : capacityIncrement)
372                    + elementData.length;
373            grow(minimumCapacity > next ? minimumCapacity : next);
374        }
375    }
376
377    /**
378     * Compares the specified object to this vector and returns if they are
379     * equal. The object must be a List which contains the same objects in the
380     * same order.
381     *
382     * @param object
383     *            the object to compare with this object
384     * @return {@code true} if the specified object is equal to this vector,
385     *         {@code false} otherwise.
386     * @see #hashCode
387     */
388    @Override
389    public synchronized boolean equals(Object object) {
390        if (this == object) {
391            return true;
392        }
393        if (object instanceof List) {
394            List<?> list = (List<?>) object;
395            if (list.size() != elementCount) {
396                return false;
397            }
398
399            int index = 0;
400            Iterator<?> it = list.iterator();
401            while (it.hasNext()) {
402                Object e1 = elementData[index++], e2 = it.next();
403                if (!(e1 == null ? e2 == null : e1.equals(e2))) {
404                    return false;
405                }
406            }
407            return true;
408        }
409        return false;
410    }
411
412    /**
413     * Returns the first element in this vector.
414     *
415     * @return the element at the first position.
416     * @throws NoSuchElementException
417     *                if this vector is empty.
418     * @see #elementAt
419     * @see #lastElement
420     * @see #size
421     */
422    @SuppressWarnings("unchecked")
423    public synchronized E firstElement() {
424        if (elementCount > 0) {
425            return (E) elementData[0];
426        }
427        throw new NoSuchElementException();
428    }
429
430    /**
431     * Returns the element at the specified location in this vector.
432     *
433     * @param location
434     *            the index of the element to return in this vector.
435     * @return the element at the specified location.
436     * @throws ArrayIndexOutOfBoundsException
437     *                if {@code location < 0 || location >= size()}.
438     * @see #size
439     */
440    @Override
441    public E get(int location) {
442        return elementAt(location);
443    }
444
445    private void grow(int newCapacity) {
446        E[] newData = newElementArray(newCapacity);
447        // Assumes elementCount is <= newCapacity
448        // assert elementCount <= newCapacity;
449        System.arraycopy(elementData, 0, newData, 0, elementCount);
450        elementData = newData;
451    }
452
453    /**
454     * JIT optimization
455     */
456    private void growByOne() {
457        int adding = 0;
458        if (capacityIncrement <= 0) {
459            if ((adding = elementData.length) == 0) {
460                adding = 1;
461            }
462        } else {
463            adding = capacityIncrement;
464        }
465
466        E[] newData = newElementArray(elementData.length + adding);
467        System.arraycopy(elementData, 0, newData, 0, elementCount);
468        elementData = newData;
469    }
470
471    private void growBy(int required) {
472        int adding = 0;
473        if (capacityIncrement <= 0) {
474            if ((adding = elementData.length) == 0) {
475                adding = required;
476            }
477            while (adding < required) {
478                adding += adding;
479            }
480        } else {
481            adding = (required / capacityIncrement) * capacityIncrement;
482            if (adding < required) {
483                adding += capacityIncrement;
484            }
485        }
486        E[] newData = newElementArray(elementData.length + adding);
487        System.arraycopy(elementData, 0, newData, 0, elementCount);
488        elementData = newData;
489    }
490
491    /**
492     * Returns an integer hash code for the receiver. Objects which are equal
493     * return the same value for this method.
494     *
495     * @return the receiver's hash.
496     * @see #equals
497     */
498    @Override
499    public synchronized int hashCode() {
500        int result = 1;
501        for (int i = 0; i < elementCount; i++) {
502            result = (31 * result)
503                    + (elementData[i] == null ? 0 : elementData[i].hashCode());
504        }
505        return result;
506    }
507
508    /**
509     * Searches in this vector for the index of the specified object. The search
510     * for the object starts at the beginning and moves towards the end of this
511     * vector.
512     *
513     * @param object
514     *            the object to find in this vector.
515     * @return the index in this vector of the specified element, -1 if the
516     *         element isn't found.
517     * @see #contains
518     * @see #lastIndexOf(Object)
519     * @see #lastIndexOf(Object, int)
520     */
521    @Override
522    public int indexOf(Object object) {
523        return indexOf(object, 0);
524    }
525
526    /**
527     * Searches in this vector for the index of the specified object. The search
528     * for the object starts at the specified location and moves towards the end
529     * of this vector.
530     *
531     * @param object
532     *            the object to find in this vector.
533     * @param location
534     *            the index at which to start searching.
535     * @return the index in this vector of the specified element, -1 if the
536     *         element isn't found.
537     * @throws ArrayIndexOutOfBoundsException
538     *                if {@code location < 0}.
539     * @see #contains
540     * @see #lastIndexOf(Object)
541     * @see #lastIndexOf(Object, int)
542     */
543    public synchronized int indexOf(Object object, int location) {
544        if (object != null) {
545            for (int i = location; i < elementCount; i++) {
546                if (object.equals(elementData[i])) {
547                    return i;
548                }
549            }
550        } else {
551            for (int i = location; i < elementCount; i++) {
552                if (elementData[i] == null) {
553                    return i;
554                }
555            }
556        }
557        return -1;
558    }
559
560    /**
561     * Inserts the specified object into this vector at the specified location.
562     * This object is inserted before any previous element at the specified
563     * location. All elements with an index equal or greater than
564     * {@code location} have their index increased by 1. If the location is
565     * equal to the size of this vector, the object is added at the end.
566     *
567     * @param object
568     *            the object to insert in this vector.
569     * @param location
570     *            the index at which to insert the element.
571     * @throws ArrayIndexOutOfBoundsException
572     *                if {@code location < 0 || location > size()}.
573     * @see #addElement
574     * @see #size
575     */
576    public synchronized void insertElementAt(E object, int location) {
577        if (location >= 0 && location <= elementCount) {
578            if (elementCount == elementData.length) {
579                growByOne();
580            }
581            int count = elementCount - location;
582            if (count > 0) {
583                System.arraycopy(elementData, location, elementData,
584                        location + 1, count);
585            }
586            elementData[location] = object;
587            elementCount++;
588            modCount++;
589        } else {
590            throw arrayIndexOutOfBoundsException(location, elementCount);
591        }
592    }
593
594    /**
595     * Returns if this vector has no elements, a size of zero.
596     *
597     * @return {@code true} if this vector has no elements, {@code false}
598     *         otherwise.
599     * @see #size
600     */
601    @Override
602    public synchronized boolean isEmpty() {
603        return elementCount == 0;
604    }
605
606    /**
607     * Returns the last element in this vector.
608     *
609     * @return the element at the last position.
610     * @throws NoSuchElementException
611     *                if this vector is empty.
612     * @see #elementAt
613     * @see #firstElement
614     * @see #size
615     */
616    @SuppressWarnings("unchecked")
617    public synchronized E lastElement() {
618        try {
619            return (E) elementData[elementCount - 1];
620        } catch (IndexOutOfBoundsException e) {
621            throw new NoSuchElementException();
622        }
623    }
624
625    /**
626     * Searches in this vector for the index of the specified object. The search
627     * for the object starts at the end and moves towards the start of this
628     * vector.
629     *
630     * @param object
631     *            the object to find in this vector.
632     * @return the index in this vector of the specified element, -1 if the
633     *         element isn't found.
634     * @see #contains
635     * @see #indexOf(Object)
636     * @see #indexOf(Object, int)
637     */
638    @Override
639    public synchronized int lastIndexOf(Object object) {
640        return lastIndexOf(object, elementCount - 1);
641    }
642
643    /**
644     * Searches in this vector for the index of the specified object. The search
645     * for the object starts at the specified location and moves towards the
646     * start of this vector.
647     *
648     * @param object
649     *            the object to find in this vector.
650     * @param location
651     *            the index at which to start searching.
652     * @return the index in this vector of the specified element, -1 if the
653     *         element isn't found.
654     * @throws ArrayIndexOutOfBoundsException
655     *                if {@code location >= size()}.
656     * @see #contains
657     * @see #indexOf(Object)
658     * @see #indexOf(Object, int)
659     */
660    public synchronized int lastIndexOf(Object object, int location) {
661        if (location < elementCount) {
662            if (object != null) {
663                for (int i = location; i >= 0; i--) {
664                    if (object.equals(elementData[i])) {
665                        return i;
666                    }
667                }
668            } else {
669                for (int i = location; i >= 0; i--) {
670                    if (elementData[i] == null) {
671                        return i;
672                    }
673                }
674            }
675            return -1;
676        }
677        throw arrayIndexOutOfBoundsException(location, elementCount);
678    }
679
680    /**
681     * Removes the object at the specified location from this vector. All
682     * elements with an index bigger than {@code location} have their index
683     * decreased by 1.
684     *
685     * @param location
686     *            the index of the object to remove.
687     * @return the removed object.
688     * @throws IndexOutOfBoundsException
689     *                if {@code location < 0 || location >= size()}.
690     */
691    @SuppressWarnings("unchecked")
692    @Override
693    public synchronized E remove(int location) {
694        if (location < elementCount) {
695            E result = (E) elementData[location];
696            elementCount--;
697            int size = elementCount - location;
698            if (size > 0) {
699                System.arraycopy(elementData, location + 1, elementData,
700                        location, size);
701            }
702            elementData[elementCount] = null;
703            modCount++;
704            return result;
705        }
706        throw arrayIndexOutOfBoundsException(location, elementCount);
707    }
708
709    /**
710     * Removes the first occurrence, starting at the beginning and moving
711     * towards the end, of the specified object from this vector. All elements
712     * with an index bigger than the element that gets removed have their index
713     * decreased by 1.
714     *
715     * @param object
716     *            the object to remove from this vector.
717     * @return {@code true} if the specified object was found, {@code false}
718     *         otherwise.
719     * @see #removeAllElements
720     * @see #removeElementAt
721     * @see #size
722     */
723    @Override
724    public boolean remove(Object object) {
725        return removeElement(object);
726    }
727
728    /**
729     * Removes all occurrences in this vector of each object in the specified
730     * Collection.
731     *
732     * @param collection
733     *            the collection of objects to remove.
734     * @return {@code true} if this vector is modified, {@code false} otherwise.
735     * @see #remove(Object)
736     * @see #contains(Object)
737     */
738    @Override
739    public synchronized boolean removeAll(Collection<?> collection) {
740        return super.removeAll(collection);
741    }
742
743    /**
744     * Removes all elements from this vector, leaving the size zero and the
745     * capacity unchanged.
746     *
747     * @see #isEmpty
748     * @see #size
749     */
750    public synchronized void removeAllElements() {
751        for (int i = 0; i < elementCount; i++) {
752            elementData[i] = null;
753        }
754        modCount++;
755        elementCount = 0;
756    }
757
758    /**
759     * Removes the first occurrence, starting at the beginning and moving
760     * towards the end, of the specified object from this vector. All elements
761     * with an index bigger than the element that gets removed have their index
762     * decreased by 1.
763     *
764     * @param object
765     *            the object to remove from this vector.
766     * @return {@code true} if the specified object was found, {@code false}
767     *         otherwise.
768     * @see #removeAllElements
769     * @see #removeElementAt
770     * @see #size
771     */
772    public synchronized boolean removeElement(Object object) {
773        int index;
774        if ((index = indexOf(object, 0)) == -1) {
775            return false;
776        }
777        removeElementAt(index);
778        return true;
779    }
780
781    /**
782     * Removes the element found at index position {@code location} from
783     * this {@code Vector}. All elements with an index bigger than
784     * {@code location} have their index decreased by 1.
785     *
786     * @param location
787     *            the index of the element to remove.
788     * @throws ArrayIndexOutOfBoundsException
789     *                if {@code location < 0 || location >= size()}.
790     * @see #removeElement
791     * @see #removeAllElements
792     * @see #size
793     */
794    public synchronized void removeElementAt(int location) {
795        if (location >= 0 && location < elementCount) {
796            elementCount--;
797            int size = elementCount - location;
798            if (size > 0) {
799                System.arraycopy(elementData, location + 1, elementData,
800                        location, size);
801            }
802            elementData[elementCount] = null;
803            modCount++;
804        } else {
805            throw arrayIndexOutOfBoundsException(location, elementCount);
806        }
807    }
808
809    /**
810     * Removes the objects in the specified range from the start to the, but not
811     * including, end index. All elements with an index bigger than or equal to
812     * {@code end} have their index decreased by {@code end - start}.
813     *
814     * @param start
815     *            the index at which to start removing.
816     * @param end
817     *            the index one past the end of the range to remove.
818     * @throws IndexOutOfBoundsException
819     *                if {@code start < 0, start > end} or
820     *                {@code end > size()}.
821     */
822    @Override
823    protected void removeRange(int start, int end) {
824        if (start >= 0 && start <= end && end <= elementCount) {
825            if (start == end) {
826                return;
827            }
828            if (end != elementCount) {
829                System.arraycopy(elementData, end, elementData, start,
830                        elementCount - end);
831                int newCount = elementCount - (end - start);
832                Arrays.fill(elementData, newCount, elementCount, null);
833                elementCount = newCount;
834            } else {
835                Arrays.fill(elementData, start, elementCount, null);
836                elementCount = start;
837            }
838            modCount++;
839        } else {
840            throw new IndexOutOfBoundsException();
841        }
842    }
843
844    /**
845     * Removes all objects from this vector that are not contained in the
846     * specified collection.
847     *
848     * @param collection
849     *            the collection of objects to retain.
850     * @return {@code true} if this vector is modified, {@code false} otherwise.
851     * @see #remove(Object)
852     */
853    @Override
854    public synchronized boolean retainAll(Collection<?> collection) {
855        return super.retainAll(collection);
856    }
857
858    /**
859     * Replaces the element at the specified location in this vector with the
860     * specified object.
861     *
862     * @param location
863     *            the index at which to put the specified object.
864     * @param object
865     *            the object to add to this vector.
866     * @return the previous element at the location.
867     * @throws ArrayIndexOutOfBoundsException
868     *                if {@code location < 0 || location >= size()}.
869     * @see #size
870     */
871    @SuppressWarnings("unchecked")
872    @Override
873    public synchronized E set(int location, E object) {
874        if (location < elementCount) {
875            E result = (E) elementData[location];
876            elementData[location] = object;
877            return result;
878        }
879        throw arrayIndexOutOfBoundsException(location, elementCount);
880    }
881
882    /**
883     * Replaces the element at the specified location in this vector with the
884     * specified object.
885     *
886     * @param object
887     *            the object to add to this vector.
888     * @param location
889     *            the index at which to put the specified object.
890     * @throws ArrayIndexOutOfBoundsException
891     *                if {@code location < 0 || location >= size()}.
892     * @see #size
893     */
894    public synchronized void setElementAt(E object, int location) {
895        if (location < elementCount) {
896            elementData[location] = object;
897        } else {
898            throw arrayIndexOutOfBoundsException(location, elementCount);
899        }
900    }
901
902    /**
903     * This method was extracted to encourage VM to inline callers.
904     * TODO: when we have a VM that can actually inline, move the test in here too!
905     */
906    private static ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException(int index, int size) {
907        throw new ArrayIndexOutOfBoundsException(size, index);
908    }
909
910    /**
911     * Sets the size of this vector to the specified size. If there are more
912     * than length elements in this vector, the elements at end are lost. If
913     * there are less than length elements in the vector, the additional
914     * elements contain null.
915     *
916     * @param length
917     *            the new size of this vector.
918     * @see #size
919     */
920    public synchronized void setSize(int length) {
921        if (length == elementCount) {
922            return;
923        }
924        ensureCapacity(length);
925        if (elementCount > length) {
926            Arrays.fill(elementData, length, elementCount, null);
927        }
928        elementCount = length;
929        modCount++;
930    }
931
932    /**
933     * Returns the number of elements in this vector.
934     *
935     * @return the number of elements in this vector.
936     * @see #elementCount
937     * @see #lastElement
938     */
939    @Override
940    public synchronized int size() {
941        return elementCount;
942    }
943
944    /**
945     * Returns a List of the specified portion of this vector from the start
946     * index to one less than the end index. The returned List is backed by this
947     * vector so changes to one are reflected by the other.
948     *
949     * @param start
950     *            the index at which to start the sublist.
951     * @param end
952     *            the index one past the end of the sublist.
953     * @return a List of a portion of this vector.
954     * @throws IndexOutOfBoundsException
955     *                if {@code start < 0} or {@code end > size()}.
956     * @throws IllegalArgumentException
957     *                if {@code start > end}.
958     */
959    @Override
960    public synchronized List<E> subList(int start, int end) {
961        return new Collections.SynchronizedRandomAccessList<E>(super.subList(
962                start, end), this);
963    }
964
965    /**
966     * Returns a new array containing all elements contained in this vector.
967     *
968     * @return an array of the elements from this vector.
969     */
970    @Override
971    public synchronized Object[] toArray() {
972        Object[] result = new Object[elementCount];
973        System.arraycopy(elementData, 0, result, 0, elementCount);
974        return result;
975    }
976
977    /**
978     * Returns an array containing all elements contained in this vector. If the
979     * specified array is large enough to hold the elements, the specified array
980     * is used, otherwise an array of the same type is created. If the specified
981     * array is used and is larger than this vector, the array element following
982     * the collection elements is set to null.
983     *
984     * @param contents
985     *            the array to fill.
986     * @return an array of the elements from this vector.
987     * @throws ArrayStoreException
988     *                if the type of an element in this vector cannot be
989     *                stored in the type of the specified array.
990     */
991    @Override
992    @SuppressWarnings("unchecked")
993    public synchronized <T> T[] toArray(T[] contents) {
994        if (elementCount > contents.length) {
995            Class<?> ct = contents.getClass().getComponentType();
996            contents = (T[]) Array.newInstance(ct, elementCount);
997        }
998        System.arraycopy(elementData, 0, contents, 0, elementCount);
999        if (elementCount < contents.length) {
1000            contents[elementCount] = null;
1001        }
1002        return contents;
1003    }
1004
1005    /**
1006     * Returns the string representation of this vector.
1007     *
1008     * @return the string representation of this vector.
1009     * @see #elements
1010     */
1011    @Override
1012    public synchronized String toString() {
1013        if (elementCount == 0) {
1014            return "[]";
1015        }
1016        int length = elementCount - 1;
1017        StringBuilder buffer = new StringBuilder(elementCount * 16);
1018        buffer.append('[');
1019        for (int i = 0; i < length; i++) {
1020            if (elementData[i] == this) {
1021                buffer.append("(this Collection)");
1022            } else {
1023                buffer.append(elementData[i]);
1024            }
1025            buffer.append(", ");
1026        }
1027        if (elementData[length] == this) {
1028            buffer.append("(this Collection)");
1029        } else {
1030            buffer.append(elementData[length]);
1031        }
1032        buffer.append(']');
1033        return buffer.toString();
1034    }
1035
1036    /**
1037     * Sets the capacity of this vector to be the same as the size.
1038     *
1039     * @see #capacity
1040     * @see #ensureCapacity
1041     * @see #size
1042     */
1043    public synchronized void trimToSize() {
1044        if (elementData.length != elementCount) {
1045            grow(elementCount);
1046        }
1047    }
1048
1049    private synchronized void writeObject(ObjectOutputStream stream)
1050            throws IOException {
1051        stream.defaultWriteObject();
1052    }
1053}
1054