FileDocCategorySizeDatePackage
IntList.javaAPI DocExample8011Sat Jan 24 10:44:24 GMT 2004je3.classes

IntList.java

/*
 * Copyright (c) 2004 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 3nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose,
 * including teaching and use in open-source projects.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book, 
 * please visit http://www.davidflanagan.com/javaexamples3.
 */
package je3.classes;

/**
 * A growable array of primitive int values.  It is more efficient than
 * ArrayList or Vector because Integer objects are not used.
 **/
public class IntList implements Comparable {
    // These are the fields of this class.
    // They are protected so that subclasses can access them directly.
    protected int[] data;    // This array holds the integers
    protected int size;      // This is how many it current holds

    // Static final values are constants.  This one is private.
    private static final int DEFAULT_CAPACITY = 8;

    // This no-argument constructor creates an IntList with a default capacity
    public IntList() { this(DEFAULT_CAPACITY); }

    // This constructor allows us to specify the initial size.  Useful when
    // we have an approximate idea of how big the list will need to be.
    public IntList(int initialCapacity) {
	// We don't have to set size to zero because newly created objects
	// automatically have their fields set to zero, false, and null.
	data = new int[initialCapacity];  // Allocate the array
    }

    // This constructor returns a copy of an existing IntList.
    public IntList(IntList original) {
	// All arrays are Cloneable, and their clone() method is an easy way
	// to copy them. Cloneable is ill-defined and hard to implement 
	// correctly, however, so it is not usually worth making your classes
	// cloneable.  A copy constructor like this one is a good alternative.
	this.data = (int[]) original.data.clone();
	this.size = original.size;
    }

    // Return the number of ints stored in the list
    public int size() { return size; }

    // Return the int stored at the specified index
    public int get(int index) {
	if (index < 0 || index >= size) // Check that argument is legitimate
	    throw new IndexOutOfBoundsException(String.valueOf(index));
	return data[index];
    }

    // Append a new value to the list, reallocating if necessary
    public void add(int value) { 
	if (size == data.length) setCapacity(size*2); // realloc if necessary
	data[size++] = value;                         // add value to list
    }

    // Set the value at the specified index
    public void set(int index, int value) {
	if (index < 0 || index >= size)
	    throw new IndexOutOfBoundsException(String.valueOf(index));
	data[index] = value;
    }

    // Shrink the list so that its capacity is the same as its size.
    // This is useful to free up unneeded memory when we know the list
    // will not have any new values added to it.
    public void trim() { setCapacity(size); }

    // Remove all elements from the list
    public void clear() { size = 0; }

    // Copy the contents of the list into a new array and return that array
    public int[] toArray() { 
	int[] copy = new int[size];
	System.arraycopy(data, 0, copy, 0, size);
	return copy;
    }

    // This is a very useful method, especially for logging and debugging.
    // Consider overriding it in every class you write.
    public String toString() {
	// Repetitive string contatenation with the + operator is inefficient.
	// It is much better to use a StringBuffer here.  In Java 1.5, use
	// StringBuilder instead.
	StringBuffer b = new StringBuffer(size*7); // Guess string length
	b.append('[');                          // Start the array
	for(int i = 0; i < size; i++) {         // Loop through list elements 
	    if (i > 0) {                        // If not the first element
		b.append(", ");                 // put a comma before it
		if (i%8 == 0) b.append('\n');   // newline every 8 elements
	    }
	    b.append(data[i]);                  // append a number
	}
	b.append(']');                          // end the array.
	return b.toString();                    // Return as a string
    }


    // Does this object contain the same values as the object o?
    // This is an Object method that we override.  Note that we must also
    // override hashCode() to match this.
    public boolean equals(Object o) {
	// If o is the same object as this, then they are equal
	if (o == this) return true;

	// If o is null or of the wrong type, it is not equal
	if (!(o instanceof IntList)) return false;

	// It is an IntList, so we can cast it, and compare this to that.
	IntList that = (IntList) o;

	// If the lists have different sizes, they are not equal
	// Note that equal lists may have different array lengths.
	if (this.size != that.size) return false;

	// If any of their elements differ then they are not equal
	for(int i = 0; i < this.size; i++)
	    if (this.data[i] != that.data[i]) return false;

	// If we get here, then the two lists contain exactly the same values
	// in the same positions, so they are equal
	return true;
    }

    // Map this object to an integer hash code used for hashtable data
    // structures.  Objects that are equal() must have the same hashCode(), so
    // we always override this method when we override equals().
    // Note that non-equal objects may have the same hashCode(), but we strive
    // to minimize that possibility.
    public int hashCode() {
	// It would be legal to just add the values up and return that as
	// the hash code, but then the list [1,2,3] would have the same hash
	// code as [3,2,1] and [3,3], which is not desired behavior.  Using
	// multiplication and addition here makes the result dependent on
	// order, and spreads codes out acros the full range of ints.
	int code = 1; // non-zero to hash [0] and [] to distinct values
	for(int i = 0; i < size; i++)
	    code = code*997 + data[i];  // ignore overflow
	return code;
    }

    /**
     * The compareTo() method is defined by the Comparable interface.
     * It defines an ordering for IntList objects and allows them to be sorted.
     *
     * Return a negative value if this object is "less than" the argument.
     * Return a postive value if this object is "greater than" the argument.
     * Return zero if the two objects are equal.
     * The first list value that differs is used to determine ordering.
     * If one list is a prefix of the other, then the longer list is greater.
     */
    public int compareTo(Object o) {
	// Cast the argument to an IntList. This will correctly throw
	// CastClassException if the wrong type is passed
	IntList that = (IntList) o;

	int n = Math.min(this.size, that.size);  // get length of shorter list
	// Compare elements of the two lists, looking for one that differs
	for(int i = 0; i < n; i++) {
	    if (this.data[i] < that.data[i]) return -1;
	    if (this.data[i] > that.data[i]) return 1;
	}

	// If we get here, then the lists are equal, or one is a prefix
	// of the other.
	return this.size - that.size;
    }

    // Reallocate the data array to enlarge or shrink it.
    // This is a non-public method used internally to grow or trim() the array.
    protected void setCapacity(int n) {
	// We use a Java 1.4 assertion to make sure the class is calling
	// this private method correctly.  Compile with "-source 1.4" to make
	// the compiler recognize this statement and run with "-ea" to make
	// the VM actually test the assertion.
	// Syntax: assert <condition> : <error message>
	assert (n >= size) : (n + "<" +size);

	if (n == data.length) return;                // Check size
	int[] newdata = new int[n];                  // Allocate the new array
	System.arraycopy(data, 0, newdata, 0, size); // Copy data into it
	data = newdata;                              // Replace old array
    }
}