/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package java.util;


import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;

/**
 * Vector is a variable size contiguous indexable array of Objects. The size of
 * the Vector is the number of Objects it contains. The capacity of the Vector
 * is the number of Objects it can hold.
 * <p>
 * Objects may be inserted at any position up to the size of the Vector,
 * increasing the size of the Vector. Objects at any position in the Vector may
 * be removed, shrinking the size of the Vector. Objects at any position in the
 * Vector may be replaced, which does not affect the Vector size.
 * <p>
 * The capacity of a Vector may be specified when the Vector is created. If the
 * capacity of the Vector is exceeded, the capacity is increased, doubling by
 * default.
 * 
 * @see java.lang.StringBuffer
 */
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess,
		Cloneable, Serializable {
	
	private static final long serialVersionUID = -2767605614048989439L;

	/**
	 * The number of elements or the size of the vector.
	 */
	protected int elementCount;

	/**
	 * The elements of the vector.
	 */
	protected Object[] elementData;

	/**
	 * How many elements should be added to the vector when it is detected that
	 * it needs to grow to accommodate extra entries.
	 */
	protected int capacityIncrement;

	private static final int DEFAULT_SIZE = 10;

	/**
	 * Constructs a new Vector using the default capacity.
	 */
	public Vector() {
		this(DEFAULT_SIZE, 0);
	}

	/**
	 * Constructs a new Vector using the specified capacity.
	 * 
	 * @param capacity
	 *            the initial capacity of the new vector
	 */
	public Vector(int capacity) {
		this(capacity, 0);
	}

	/**
	 * Constructs a new Vector using the specified capacity and capacity
	 * increment.
	 * 
	 * @param capacity
	 *            the initial capacity of the new Vector
	 * @param capacityIncrement
	 *            the amount to increase the capacity when this Vector is full
	 */
	public Vector(int capacity, int capacityIncrement) {
		elementCount = 0;
		try {
			elementData = newElementArray(capacity);
		} catch (NegativeArraySizeException e) {
			throw new IllegalArgumentException();
		}
		this.capacityIncrement = capacityIncrement;
	}

	/**
	 * Constructs a new instance of <code>Vector</code> containing the
	 * elements in <code>collection</code>. The order of the elements in the
	 * new <code>Vector</code> is dependent on the iteration order of the seed
	 * collection.
	 * 
	 * @param collection
	 *            the collection of elements to add
	 */
	public Vector(Collection<? extends E> collection) {
		this(collection.size(), 0);
		Iterator<? extends E> it = collection.iterator();
		while (it.hasNext()) {
            elementData[elementCount++] = it.next();
        }
	}
    
    @SuppressWarnings("unchecked")
    private E[] newElementArray(int size) {
        return (E[])new Object[size];
    }

	/**
	 * Adds the specified object into this Vector at the specified location. The
	 * object is inserted before any previous element at the specified location.
	 * If the location is equal to the size of this Vector, the object is added
	 * at the end.
	 * 
	 * @param location
	 *            the index at which to insert the element
	 * @param object
	 *            the object to insert in this Vector
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location < 0 || > size()</code>
	 * 
	 * @see #addElement
	 * @see #size
	 */
	@Override
    public void add(int location, E object) {
		insertElementAt(object, location);
	}

	/**
	 * Adds the specified object at the end of this Vector.
	 * 
	 * @param object
	 *            the object to add to the Vector
	 * @return true
	 */
	@Override
    public boolean add(E object) {
		addElement(object);
		return true;
	}

	/**
	 * Inserts the objects in the specified Collection at the specified location
	 * in this Vector. The objects are inserted in the order in which they are
	 * returned from the Collection iterator.
	 * 
	 * @param location
	 *            the location to insert the objects
	 * @param collection
	 *            the Collection of objects
	 * @return true if this Vector is modified, false otherwise
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location < 0</code> or
	 *                <code>location > size()</code>
	 */
	@Override
    public synchronized boolean addAll(int location, Collection<? extends E> collection) {
		if (0 <= location && location <= elementCount) {
			int size = collection.size();
			if (size == 0) {
                return false;
            }
			int required = size - (elementData.length - elementCount);
			if (required > 0) {
                growBy(required);
            }
			int count = elementCount - location;
			if (count > 0) {
                System.arraycopy(elementData, location, elementData, location
						+ size, count);
            }
			Iterator<? extends E> it = collection.iterator();
			while (it.hasNext()) {
                elementData[location++] = it.next();
            }
			elementCount += size;
			modCount++;
			return true;
		}
        throw new ArrayIndexOutOfBoundsException(location);
	}

	/**
	 * Adds the objects in the specified Collection to the end of this Vector.
	 * 
	 * @param collection
	 *            the Collection of objects
	 * @return true if this Vector is modified, false otherwise
	 */
	@Override
    public synchronized boolean addAll(Collection<? extends E> collection) {
		return addAll(elementCount, collection);
	}

	/**
	 * Adds the specified object at the end of this Vector.
	 * 
	 * @param object
	 *            the object to add to the Vector
	 */
	public synchronized void addElement(E object) {
		if (elementCount == elementData.length) {
            growByOne();
        }
		elementData[elementCount++] = object;
		modCount++;
	}

	/**
	 * Answers the number of elements this Vector can hold without growing.
	 * 
	 * @return the capacity of this Vector
	 * 
	 * @see #ensureCapacity
	 * @see #size
	 */
	public synchronized int capacity() {
		return elementData.length;
	}

	/**
	 * Removes all elements from this Vector, leaving it empty.
	 * 
	 * @see #isEmpty
	 * @see #size
	 */
	@Override
    public void clear() {
		removeAllElements();
	}

	/**
	 * Answers a new Vector with the same elements, size, capacity and capacity
	 * increment as this Vector.
	 * 
	 * @return a shallow copy of this Vector
	 * 
	 * @see java.lang.Cloneable
	 */
	@Override
    @SuppressWarnings("unchecked")
    public synchronized Object clone() {
		try {
			Vector<E> vector = (Vector<E>) super.clone();
			vector.elementData = elementData.clone();
			return vector;
		} catch (CloneNotSupportedException e) {
			return null;
		}
	}

	/**
	 * Searches this Vector for the specified object.
	 * 
	 * @param object
	 *            the object to look for in this Vector
	 * @return true if object is an element of this Vector, false otherwise
	 * 
	 * @see #indexOf(Object)
	 * @see #indexOf(Object, int)
	 * @see java.lang.Object#equals
	 */
	@Override
    public boolean contains(Object object) {
		return indexOf(object, 0) != -1;
	}

	/**
	 * Searches this Vector for all objects in the specified Collection.
	 * 
	 * @param collection
	 *            the Collection of objects
	 * @return true if all objects in the specified Collection are elements of
	 *         this Vector, false otherwise
	 */
	@Override
    public synchronized boolean containsAll(Collection<?> collection) {
		return super.containsAll(collection);
	}

	/**
	 * Attempts to copy elements contained by this <code>Vector</code> into
	 * the corresponding elements of the supplied <code>Object</code> array.
	 * 
	 * @param elements
	 *            the <code>Object</code> array into which the elements of
	 *            this Vector are copied
	 * 
	 * @see #clone
	 */
	public synchronized void copyInto(Object[] elements) {
		System.arraycopy(elementData, 0, elements, 0, elementCount);
	}

	/**
	 * Answers the element at the specified location in this Vector.
	 * 
	 * @param location
	 *            the index of the element to return in this Vector
	 * @return the element at the specified location
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location < 0 || >= size()</code>
	 * 
	 * @see #size
	 */
	public synchronized E elementAt(int location) {
		if (location < elementCount) {
			return (E)elementData[location];
		}
		throw new ArrayIndexOutOfBoundsException(location);
	}

	/**
	 * Answers an Enumeration on the elements of this Vector. The results of the
	 * Enumeration may be affected if the contents of this Vector are modified.
	 * 
	 * @return an Enumeration of the elements of this Vector
	 * 
	 * @see #elementAt
	 * @see Enumeration
	 */
	public Enumeration<E> elements() {
		return new Enumeration<E>() {
			int pos = 0;

			public boolean hasMoreElements() {
				return pos < elementCount;
			}

			public E nextElement() {
				synchronized (Vector.this) {
					if (pos < elementCount) {
						return (E)elementData[pos++];
					}
				}
				throw new NoSuchElementException();
			}
		};
	}

	/**
	 * Ensures that this Vector can hold the specified number of elements
	 * without growing.
	 * 
	 * @param minimumCapacity
	 *            the minimum number of elements that this vector will hold
	 *            before growing
	 * 
	 * @see #capacity
	 */
	public synchronized void ensureCapacity(int minimumCapacity) {
		if (elementData.length < minimumCapacity) {
			int next = (capacityIncrement <= 0 ? elementData.length
					: capacityIncrement)
					+ elementData.length;
			grow(minimumCapacity > next ? minimumCapacity : next);
		}
	}

	/**
	 * Compares the specified object to this Vector and answer if they are
	 * equal. The object must be a List which contains the same objects in the
	 * same order.
	 * 
	 * @param object
	 *            the object to compare with this object
	 * @return true if the specified object is equal to this Vector, false
	 *         otherwise
	 * 
	 * @see #hashCode
	 */
	@Override
    public synchronized boolean equals(Object object) {
		if (this == object) {
            return true;
        }
		if (object instanceof List) {
			List<?> list = (List) object;
			if (list.size() != size()) {
                return false;
            }

			int index = 0;
			Iterator<?> it = list.iterator();
			while (it.hasNext()) {
				Object e1 = elementData[index++], e2 = it.next();
				if (!(e1 == null ? e2 == null : e1.equals(e2))) {
                    return false;
                }
			}
			return true;
		}
		return false;
	}

	/**
	 * Answers the first element in this Vector.
	 * 
	 * @return the element at the first position
	 * 
	 * @exception NoSuchElementException
	 *                when this vector is empty
	 * 
	 * @see #elementAt
	 * @see #lastElement
	 * @see #size
	 */
	public synchronized E firstElement() {
		if (elementCount > 0) {
			return (E)elementData[0];
		}
		throw new NoSuchElementException();
	}

	/**
	 * Answers the element at the specified location in this Vector.
	 * 
	 * @param location
	 *            the index of the element to return in this Vector
	 * @return the element at the specified location
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location < 0 || >= size()</code>
	 * 
	 * @see #size
	 */
	@Override
    public E get(int location) {
		return elementAt(location);
	}

	private void grow(int newCapacity) {
		E[] newData = newElementArray(newCapacity);
		// Assumes elementCount is <= newCapacity
        assert elementCount <= newCapacity;
		System.arraycopy(elementData, 0, newData, 0, elementCount); 
		elementData = newData;
	}

	/**
	 * JIT optimization
	 */
	private void growByOne() {
		int adding = 0;
		if (capacityIncrement <= 0) {
			if ((adding = elementData.length) == 0) {
                adding = 1;
            }
		} else {
            adding = capacityIncrement;
        }

		E[] newData = newElementArray(elementData.length + adding);
		System.arraycopy(elementData, 0, newData, 0, elementCount);
		elementData = newData;
	}

	private void growBy(int required) {
		int adding = 0;
		if (capacityIncrement <= 0) {
			if ((adding = elementData.length) == 0) {
                adding = required;
            }
			while (adding < required) {
                adding += adding;
            }
		} else {
			adding = (required / capacityIncrement) * capacityIncrement;
			if (adding < required) {
                adding += capacityIncrement;
            }
		}
		E[] newData = newElementArray(elementData.length + adding);
		System.arraycopy(elementData, 0, newData, 0, elementCount);
		elementData = newData;
	}

	/**
	 * Answers an integer hash code for the receiver. Objects which are equal
	 * answer the same value for this method.
	 * 
	 * @return the receiver's hash
	 * 
	 * @see #equals
	 */
	@Override
    public synchronized int hashCode() {
		int result = 1;
		for (int i = 0; i < elementCount; i++) {
            result = (31 * result)
					+ (elementData[i] == null ? 0 : elementData[i].hashCode());
        }
		return result;
	}

	/**
	 * Searches in this Vector for the index of the specified object. The search
	 * for the object starts at the beginning and moves towards the end of this
	 * Vector.
	 * 
	 * @param object
	 *            the object to find in this Vector
	 * @return the index in this Vector of the specified element, -1 if the
	 *         element isn't found
	 * 
	 * @see #contains
	 * @see #lastIndexOf(Object)
	 * @see #lastIndexOf(Object, int)
	 */
	@Override
    public int indexOf(Object object) {
		return indexOf(object, 0);
	}

	/**
	 * Searches in this Vector for the index of the specified object. The search
	 * for the object starts at the specified location and moves towards the end
	 * of this Vector.
	 * 
	 * @param object
	 *            the object to find in this Vector
	 * @param location
	 *            the index at which to start searching
	 * @return the index in this Vector of the specified element, -1 if the
	 *         element isn't found
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location < 0</code>
	 * 
	 * @see #contains
	 * @see #lastIndexOf(Object)
	 * @see #lastIndexOf(Object, int)
	 */
	public synchronized int indexOf(Object object, int location) {
		if (object != null) {
			for (int i = location; i < elementCount; i++) {
                if (object.equals(elementData[i])) {
                    return i;
                }
            }
		} else {
			for (int i = location; i < elementCount; i++) {
                if (elementData[i] == null) {
                    return i;
                }
            }
		}
		return -1;
	}

	/**
	 * Inserts the specified object into this Vector at the specified location.
	 * This object is inserted before any previous element at the specified
	 * location. If the location is equal to the size of this Vector, the object
	 * is added at the end.
	 * 
	 * @param object
	 *            the object to insert in this Vector
	 * @param location
	 *            the index at which to insert the element
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location < 0 || > size()</code>
	 * 
	 * @see #addElement
	 * @see #size
	 */
	public synchronized void insertElementAt(E object, int location) {
		if (0 <= location && location <= elementCount) {
			if (elementCount == elementData.length) {
                growByOne();
            }
			int count = elementCount - location;
			if (count > 0) {
                System.arraycopy(elementData, location, elementData,
						location + 1, count);
            }
			elementData[location] = object;
			elementCount++;
			modCount++;
		} else {
            throw new ArrayIndexOutOfBoundsException(location);
        }
	}

	/**
	 * Answers if this Vector has no elements, a size of zero.
	 * 
	 * @return true if this Vector has no elements, false otherwise
	 * 
	 * @see #size
	 */
	@Override
    public synchronized boolean isEmpty() {
		return elementCount == 0;
	}

	/**
	 * Answers the last element in this Vector.
	 * 
	 * @return the element at the last position
	 * 
	 * @exception NoSuchElementException
	 *                when this vector is empty
	 * 
	 * @see #elementAt
	 * @see #firstElement
	 * @see #size
	 */
	public synchronized E lastElement() {
		try {
			return (E)elementData[elementCount - 1];
		} catch (IndexOutOfBoundsException e) {
			throw new NoSuchElementException();
		}
	}

	/**
	 * Searches in this Vector for the index of the specified object. The search
	 * for the object starts at the end and moves towards the start of this
	 * Vector.
	 * 
	 * @param object
	 *            the object to find in this Vector
	 * @return the index in this Vector of the specified element, -1 if the
	 *         element isn't found
	 * 
	 * @see #contains
	 * @see #indexOf(Object)
	 * @see #indexOf(Object, int)
	 */
	@Override
    public synchronized int lastIndexOf(Object object) {
		return lastIndexOf(object, elementCount - 1);
	}

	/**
	 * Searches in this Vector for the index of the specified object. The search
	 * for the object starts at the specified location and moves towards the
	 * start of this Vector.
	 * 
	 * @param object
	 *            the object to find in this Vector
	 * @param location
	 *            the index at which to start searching
	 * @return the index in this Vector of the specified element, -1 if the
	 *         element isn't found
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location >= size()</code>
	 * 
	 * @see #contains
	 * @see #indexOf(Object)
	 * @see #indexOf(Object, int)
	 */
	public synchronized int lastIndexOf(Object object, int location) {
		if (location < elementCount) {
			if (object != null) {
				for (int i = location; i >= 0; i--) {
                    if (object.equals(elementData[i])) {
                        return i;
                    }
                }
			} else {
				for (int i = location; i >= 0; i--) {
                    if (elementData[i] == null) {
                        return i;
                    }
                }
			}
			return -1;
		}
        throw new ArrayIndexOutOfBoundsException(location);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.List#remove(int)
	 */
	@Override
    public synchronized E remove(int location) {
		if (location < elementCount) {
			E result = (E)elementData[location];
			elementCount--;
			int size = elementCount - location;
			if (size > 0) {
                System.arraycopy(elementData, location + 1, elementData,
						location, size);
            }
			elementData[elementCount] = null;
			modCount++;
			return result;
		}
        throw new ArrayIndexOutOfBoundsException(location);
	}

	/**
	 * Removes the first occurrence, starting at the beginning and moving
	 * towards the end, of the specified object from this Vector.
	 * 
	 * @param object
	 *            the object to remove from this Vector
	 * @return true if the specified object was found, false otherwise
	 * 
	 * @see #removeAllElements
	 * @see #removeElementAt
	 * @see #size
	 */
	@Override
    public boolean remove(Object object) {
		return removeElement(object);
	}

	/**
	 * Removes all occurrences in this Vector of each object in the specified
	 * Collection.
	 * 
	 * @param collection
	 *            the Collection of objects to remove
	 * @return true if this Vector is modified, false otherwise
	 */
	@Override
    public synchronized boolean removeAll(Collection<?> collection) {
		return super.removeAll(collection);
	}

	/**
	 * Removes all elements from this Vector, leaving the size zero and the
	 * capacity unchanged.
	 * 
	 * @see #isEmpty
	 * @see #size
	 */
	public synchronized void removeAllElements() {
		Arrays.fill(elementData, 0, elementCount, null);
		modCount++;
		elementCount = 0;
	}

	/**
	 * Removes the first occurrence, starting at the beginning and moving
	 * towards the end, of the specified object from this Vector.
	 * 
	 * @param object
	 *            the object to remove from this Vector
	 * @return true if the specified object was found, false otherwise
	 * 
	 * @see #removeAllElements
	 * @see #removeElementAt
	 * @see #size
	 */
	public synchronized boolean removeElement(Object object) {
		int index;
		if ((index = indexOf(object, 0)) == -1) {
            return false;
        }
		removeElementAt(index);
		return true;
	}

	/**
	 * Removes the element found at index position <code>location</code> from
	 * this <code>Vector</code> and decrements the size accordingly.
	 * 
	 * @param location
	 *            the index of the element to remove
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location < 0 || >= size()</code>
	 * 
	 * @see #removeElement
	 * @see #removeAllElements
	 * @see #size
	 */
	public synchronized void removeElementAt(int location) {
		if (0 <= location && location < elementCount) {
			elementCount--;
			int size = elementCount - location;
			if (size > 0) {
                System.arraycopy(elementData, location + 1, elementData,
						location, size);
            }
			elementData[elementCount] = null;
			modCount++;
		} else {
            throw new ArrayIndexOutOfBoundsException(location);
        }
	}

	/**
	 * Removes the objects in the specified range from the start to the, but not
	 * including, end index.
	 * 
	 * @param start
	 *            the index at which to start removing
	 * @param end
	 *            the index one past the end of the range to remove
	 * 
	 * @exception IndexOutOfBoundsException
	 *                when <code>start < 0, start > end</code> or
	 *                <code>end > size()</code>
	 */
	@Override
    protected void removeRange(int start, int end) {
		if (start >= 0 && start <= end && end <= size()) {
			if (start == end) {
                return;
            }
			if (end != elementCount) {
				System.arraycopy(elementData, end, elementData, start,
						elementCount - end);
				int newCount = elementCount - (end - start);
				Arrays.fill(elementData, newCount, elementCount, null);
				elementCount = newCount;
			} else {
				Arrays.fill(elementData, start, elementCount, null);
				elementCount = start;
			}
			modCount++;
		} else {
            throw new IndexOutOfBoundsException();
        }
	}

	/**
	 * Removes all objects from this Vector that are not contained in the
	 * specified Collection.
	 * 
	 * @param collection
	 *            the Collection of objects to retain
	 * @return true if this Vector is modified, false otherwise
	 */
	@Override
    public synchronized boolean retainAll(Collection<?> collection) {
		return super.retainAll(collection);
	}

	/**
	 * Replaces the element at the specified location in this Vector with the
	 * specified object.
	 * 
	 * @param location
	 *            the index at which to put the specified object
	 * @param object
	 *            the object to add to this Vector
	 * @return the previous element at the location
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location < 0 || >= size()</code>
	 * 
	 * @see #size
	 */
	@Override
    public synchronized E set(int location, E object) {
		if (location < elementCount) {
			E result = (E)elementData[location];
			elementData[location] = object;
			return result;
		}
        throw new ArrayIndexOutOfBoundsException(location);
	}

	/**
	 * Replaces the element at the specified location in this Vector with the
	 * specified object.
	 * 
	 * @param object
	 *            the object to add to this Vector
	 * @param location
	 *            the index at which to put the specified object
	 * 
	 * @exception ArrayIndexOutOfBoundsException
	 *                when <code>location < 0 || >= size()</code>
	 * 
	 * @see #size
	 */
	public synchronized void setElementAt(E object, int location) {
		if (location < elementCount) {
            elementData[location] = object;
        } else {
            throw new ArrayIndexOutOfBoundsException(location);
        }
	}

	/**
	 * Sets the size of this Vector to the specified size. If there are more
	 * than length elements in this Vector, the elements at end are lost. If
	 * there are less than length elements in the Vector, the additional
	 * elements contain null.
	 * 
	 * @param length
	 *            the new size of this Vector
	 * 
	 * @see #size
	 */
	public synchronized void setSize(int length) {
		if (length == elementCount) {
            return;
        }
		ensureCapacity(length);
		if (elementCount > length) {
			Arrays.fill(elementData, length, elementCount, null);
		}
		elementCount = length;
		modCount++;
	}

	/**
	 * Answers the number of elements in this Vector.
	 * 
	 * @return the number of elements in this Vector
	 * 
	 * @see #elementCount
	 * @see #lastElement
	 */
	@Override
    public synchronized int size() {
		return elementCount;
	}

	/**
	 * Answers a List of the specified portion of this Vector from the start
	 * index to one less than the end index. The returned List is backed by this
	 * Vector so changes to one are reflected by the other.
	 * 
	 * @param start
	 *            the index at which to start the sublist
	 * @param end
	 *            the index one past the end of the sublist
	 * @return a List of a portion of this Vector
	 * 
	 * @exception IndexOutOfBoundsException
	 *                when <code>start < 0 or <code>end > size()</code>
	 * @exception	IllegalArgumentException when <code>start > end</code>
	 */
	@Override
    public synchronized List<E> subList(int start, int end) {
		return new Collections.SynchronizedRandomAccessList<E>(
                super.subList(start, end), this);
	}

	/**
	 * Answers a new array containing all elements contained in this Vector.
	 * 
	 * @return an array of the elements from this Vector
	 */
	@Override
    public synchronized Object[] toArray() {
		Object[] result = new Object[elementCount];
		System.arraycopy(elementData, 0, result, 0, elementCount);
		return result;
	}

	/**
	 * Answers an array containing all elements contained in this Vector. If the
	 * specified array is large enough to hold the elements, the specified array
	 * is used, otherwise an array of the same type is created. If the specified
	 * array is used and is larger than this Vector, the array element following
	 * the collection elements is set to null.
	 * 
	 * @param contents
	 *            the array
	 * @return an array of the elements from this Vector
	 * 
	 * @exception ArrayStoreException
	 *                when the type of an element in this Vector cannot be
	 *                stored in the type of the specified array
	 */
	@Override
    @SuppressWarnings("unchecked")
    public synchronized <T> T[] toArray(T[] contents) {
		if (elementCount > contents.length) {
            Class<?> ct = contents.getClass().getComponentType();
			contents = (T[]) Array.newInstance(ct, elementCount);
        }
		System.arraycopy(elementData, 0, contents, 0, elementCount);
		if (elementCount < contents.length) {
            contents[elementCount] = null;
        }
		return contents;
	}

	/**
	 * Answers the string representation of this Vector.
	 * 
	 * @return the string representation of this Vector
	 * 
	 * @see #elements
	 */
	@Override
    public synchronized String toString() {
		if (elementCount == 0) {
            return "[]";
        }
		int length = elementCount - 1;
		StringBuffer buffer = new StringBuffer(size() * 16);
		buffer.append('[');
		for (int i = 0; i < length; i++) {
			if (elementData[i] == this) {
				buffer.append("(this Collection)");
			} else {
				buffer.append(elementData[i]);
			}
			buffer.append(", ");
		}
		if (elementData[length] == this) {
			buffer.append("(this Collection)");
		} else {
			buffer.append(elementData[length]);
		}
		buffer.append(']');
		return buffer.toString();
	}

	/**
	 * Sets the capacity of this Vector to be the same as the size.
	 * 
	 * @see #capacity
	 * @see #ensureCapacity
	 * @see #size
	 */
	public synchronized void trimToSize() {
		if (elementData.length != elementCount) {
            grow(elementCount);
        }
	}

	private synchronized void writeObject(ObjectOutputStream stream)
			throws IOException {
		stream.defaultWriteObject();
	}
}
