Title: List
Course: CPS 261: Advanced Java Concepts ~ DL & MM MASTER

The Collections Framework

At some point, you will find that you want more support than simple Arrays can provide. In Computer Science, you can spend a whole semester studying datastructures and all of the various ways that data can be stored. Depending on what your primary operations are, you might choose a datastructure that is the most efficient for the normal operations that you encounter. Every datastructure has its own advantages and disadvantages.

First of all let's look at the characteristics of simple arrays.

1. Arrays are efficient.
2. You can store Classes, or primitives(int, long, double, etc.) in arrays.
3. You have to know how many elements that are required up front. Otherwise, you end up writing code to create a larger array and copy the previous array into the new bigger array.
4. Minimal software for working with Arrays. Difficult to insert into the middle of the array, etc. Using the Collection classes provides a large amount of supporting software and makes life easier than using simple arrays.

Why Use the Collections Framework?

1. Reduces programming effort -methods such as sorting algorithms are already written.
2. Increases program speed and quality.
3. By providing standard interfaces, its easier to integrate modules together.
4. Standard interfaces make it easier to learn how to use the classes available.

Standard Interfaces in the Collections Framework

Java has defined some standard Interfaces that describe the standard datastructures needed. Many of these standard Interfaces and Classes are based on a top level Collection interface. There is also a Map interface that we will talk about later.

- interface Collection - This is the most generic interface. This interface defines some simple methods that are generic to a large number of datastructures. This interface does not impose many constraints on the type of datastructure. The Collection class is a parent interface to several other interfaces
  - interface List extends Collection- The List interface is derived from the Collection class. The List class represents an ordered Collection. Ordered does not imply sorted. An Array can be considered ordered because each element has a specific index that can be used to access the element. A List can store duplicate elements.
    - class ArrayList - This is a class which implements the List interface. ArrayList can be thought of as an array of Objects that can dynamically grow as needed. The ArrayList class is good if you have to index your datastructure similar to array accesses.
    - class Vector - This class implements the List interface and is very similar to ArrayList. The Vector class has been around longer than the ArrayList and carries some backwards compatible baggage. It's good to know about the Vector class, because many java examples use it because its well known and been around a long time.
    - class LinkedList - This class implements the List interface and is designed to work well with linked lists, especially Queues.
  - interface Set extends Collection - The methods in Set are the same as in the Collection interface. However a Set adds the characteristic that you can't have duplicate objects in a Set. If you are a mathematician you may be familiar with the idea of Set operations. In math, you can do unions, and intersections of Sets. Although you won't see methods for union and intersection in the Set interface, it's easy to build it from the primitives.
    - class HashSet - an implementation of the Set interface.
  - interface SortedSet extends Set - A Set with the added constraint that the data stays sorted
    - class TreeSet - an implementation of SortedSet

interface Collection

Proto-Type | Description
boolean add(Object o) | Ensures that this collection contains the specified element (optional operation).
void clear() | Removes all of the elements from this collection (optional operation).
boolean contains(Object o) | Returns true if this collection contains the specified element.
boolean isEmpty() | Returns true if this collection contains no elements.
Iterator iterator() | Returns an iterator over the elements in this collection.
boolean remove(Object o) | Removes a single instance of the specified element from this collection, if it is present (optional operation). boolean retainAll(Collection c) Retains only the elements in this collection that are contained in the specified collection (optional operation).
int size() | Returns the number of elements in this collection.
Object[] toArray() | Returns an array containing all of the elements in this collection.
Object[] toArray(Object[] a) | Returns an array containing all of the elements in this collection whose runtime type is that of the specified array.

interface Iterator

When working with Collections classes, its often good to be able to list all of the members of a collection. For a simple array type of collection, this is not a problem. However, some of our collections are trees, or hashmaps which do not have a simple array concept associated with them. For this reason, the Iterator class is a standard way to list all the elements in a Collection. It only has 3 methods ( the remove method is not used very often). We will demonstrate its usage in the first example.

The concept of an Iterator shows up a lot in advanced Java concepts. You will see it in Java Servlets, Jdbc, and XML.

One side note --- It's not a good idea to be half way through an iterator and decide to add another element to the Collection. This can cause problems.

There is also an older variation of an Iterator that was in used in Java 1.1 called Enumeration. The method names are a little different, but the concept is the same. An Enumeration contains the methods:
hasMoreElements()
nextElement()

Proto-Type | Description
boolean hasNext() | Returns true if the iteration has more elements.
Object next() | Returns the next element in the interation.
void remove() | Removes from the underlying collection the last element returned by the iterator (optional operation).

TryCollection.java


import tools.*;
import java.util.*;
class TryCollection
{
    // ArrayList is an implementation of the List interface
    // which is derived from the Interface
    // Note that we are only using methods in the Collection Interface.
    // This means that you can replace the ArrayList with
    // Vector, LinkedList, HashSet, or TreeSet
    // and the rest of this code will work the same.
    Collection store = new ArrayList();
    void load(String file)
    {
        String str;
        MyInput in = new MyInput(file);
        do
        {
            str = in.get();
            if (str != null)
            {
                str = str.trim();
                store.add(str);
            }

        }while (str != null);
        // Execute toString method on ArrayList
        System.out.println(store);
    }

    void iterate()
    {
        System.out.println("***********************************");
        System.out.println("Iterator:");
        System.out.println("-----");
        Iterator iter = store.iterator();
        while(iter.hasNext())
            System.out.println(iter.next());
    }
    void toArray()
    {
        System.out.println("******** toArray() ********");
        Object [] objArr = store.toArray();
        for (int i = 0; i< objArr.length; i++)
            System.out.println(objArr[i]);

    }


    void toStrArray()
    {
        System.out.println("******** toStrArray() ********");
        String [] strArr = (String[])store.toArray(new String[0]);
        for (int i = 0; i< strArr.length; i++)
            System.out.println(strArr[i]);

    }
    void doCmd(MyInput input, String str)
    {
     if (str.equals("load"))
            {
                System.out.println("Enter filename to load");
                str = input.get();
                load(str);
            }
      else if (str.equals("iterate")) iterate();
      else if (str.equals("clear"))
                store.clear();
      else if (str.equals("isEmpty"))
                System.out.println("isEmpty = " +
                    store.isEmpty());
      else if (str.equals("size"))
                System.out.println("size = "+
                     store.size());
      else if (str.equals("toString"))
                System.out.println(store);
      else if (str.equals("toArray")) toArray();
      else if (str.equals("toStrArray")) toStrArray();
      else if (str.equals("contains"))
            {
                System.out.println("contains what ?");
                str = input.get();
                System.out.println("contains(" + str + ") = " +
                    store.contains(str));
            }
      else if (str.equals("add"))
            {
                System.out.println("add what ?");
                str = input.get();
                System.out.println("adds(" + str + ") = " +
                    store.add(str));
            }
      else if (str.equals("remove"))
            {
                System.out.println("remove what ?");
                str = input.get();
                System.out.println("remove(" + str + ") = " +
                    store.remove(str));
            }
      else System.out.println("Illegal command");
    }
    public static void main(String[] args)
    {
        TryCollection doit = new TryCollection();
        String str;
        MyInput input = new MyInput();
        do
        {
            System.out.println(" **********************************");
            System.out.println("enter load, add, clear, contains, isEmpty, ");
            System.out.println("remove, size, toString, toArray, toStrArray, or iterate");
            System.out.println(" -----------------------");
            str = input.get();
            str = str.trim();
	
            doit.doCmd(input, str);
        } while (str != null);
    }
}


To run this program it is helpful to have a file containing a list of names. You can load in names from:
name.txt

interface List extends Collection

If your collection has some concept of order, then you might want to work with the List interface. ArrayLists, and LinkedLists are the standard datastructures that have some sense of order. This means that you can index the list by some index number.

An ArrayList is good if your primary operation is random accessing of the datastructure by index. Adding to the end of the ArrayList is fast , but adding anywhere else is inefficient because you have to slide everything else down.

A LinkedList is good for Queues. A LinkedList is not as fast for accessing elements by index. But a LinkedList is faster for inserting a new element anywhere in the list. LinkedLists are especially good when you primarily access data off the front or the end of the list.

Proto-Type | Description
void add(int index, Object element) | Inserts the specified element at the specified position in this list (optional operation).
Object get(int index) | Returns the element at the specified position in this list.
int indexOf(Object o) | Returns the index in this list of the first occurrence of the specified element, or -1 if this list does not contain this element.
int lastIndexOf(Object o) | Returns the index in this list of the last occurrence of the specified element, or -1 if this list does not contain this element.
ListIterator listIterator() | Returns a list iterator of the elements in this list (in proper sequence).
Object remove(int index) | Removes the element at the specified position in this list (optional operation).
Object set(int index, Object element) | Replaces the element at the specified position in this list with the specified element (optional operation).
List subList(int fromIndex, int toIndex) | Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.

interface listIterator extends Iterator

If your Collection is actually a List, then you can get a fancier Iterator than the simple one shown above. The listIterator has everything that a regular Iterator has plus the methods show in the table below. The methods available in this interface allow you to move backwards as well as forward. Also you can change data as you walk through the iterator. Not the set, and add routines.

Proto-Type | Description
void add(Object o) | Inserts the specified element into the list (optional operation).
boolean hasPrevious() | Returns true if this list iterator has more elements when traversing the list in the reverse direction.
int nextIndex() | Returns the index of the element that would be returned by a subsequent call to next.
Object previous() | Returns the previous element in the list.
int previousIndex() | Returns the index of the element that would be returned by a subsequent call to previous.
void set(Object o) | Replaces the last element returned by next or previous with the specified element (optional operation).

TryList.java


import tools.*;
import java.util.*;
class TryList
{
    List store = new ArrayList();
    void load(String file)
    {
        String str;
        MyInput in = new MyInput(file);
        do
        {
            str = in.get();
            if (str != null)
            {
                str = str.trim();
                store.add(str);
            }

        }while (str != null);
        System.out.println(store);
    }

    void listIterator()
    {
        System.out.println("***********************************");
        //Not demoing very many of the listIterator features
        System.out.println("listIterator:");
        System.out.println("-----");
        ListIterator iter = store.listIterator();
        while(iter.hasNext())
            System.out.println(iter.next() + " previousIndex=" + iter.previousIndex() +
                " nextIndex=" + iter.nextIndex());
    }
    void subList(int start, int end)
    {
        List sub = store.subList(start,end);
        System.out.println("******** subList() ********");
        for (int i = 0; i< sub.size(); i++)
            System.out.println(sub.get(i));

    }
    void doCmd(MyInput input, String str)
    {
      int index, index2;
      if (str.equals("load"))
            {
                System.out.println("Enter filename to load");
                str = input.get();
                load(str);
            }
       else if (str.equals("listIterator")) listIterator();
       else if (str.equals("toString"))
                System.out.println(store);
       else if (str.equals("subList"))
            {
                System.out.println("Enter start index");
                index = input.getInt();
                System.out.println("Enter end index");
                index2 = input.getInt();
                subList(index, index2);
            }
       else if (str.equals("indexOf"))
            {
                System.out.println("indexOf value ?");
                str = input.get();
                System.out.println("indexOf(value) = " +
                    store.indexOf(str) );
            }
       else if (str.equals("lastIndexOf"))
            {
                System.out.println("lastIndexOf value ?");
                str = input.get();
                System.out.println("lastIndexOf(value) = " +
                    store.lastIndexOf(str) );
            }
       else if (str.equals("set"))
            {
                System.out.println("set index?");
                index = input.getInt();
                System.out.println("set value ?");
                str = input.get();
                System.out.println("set(index,obj) = " +
                    store.set(index, str) );
            }
       else if (str.equals("get"))
            {
                System.out.println("get index?");
                index = input.getInt();
                System.out.println("get(index) = " +
                    store.get(index) );
            }
       else if (str.equals("add"))
            {
                System.out.println("add index?");
                index = input.getInt();
                System.out.println("add what ?");
                str = input.get();
                System.out.println("adds(index,obj) " );
                store.add(index, str);
            }
       else if (str.equals("remove"))
            {
                System.out.println("remove index?");
                index = input.getInt();
                System.out.println("remove(index) = " +
                    store.remove(index));
            } 	
       else System.out.println("Illegal command");
    }
    public static void main(String[] args)
    {
        TryList doit = new TryList();
        String str;
        MyInput input = new MyInput();
        do
        {
            System.out.println(" **********************************");
            System.out.println("enter load, add(index,ob), get, indexOf, lastIndexOf,  ");
            System.out.println("remove(index), set, toString, subList or listIterator");
            System.out.println(" -----------------------");
            str = input.get();
            str = str.trim();

            doit.doCmd(input, str);
        } while (str != null);
    }


}


Collections Class

Note the difference between the Interface Collection and the Class Collections. One of the payoffs to using standard Java classes is that you can get standard code already written for you. If you have a class which implements List, you can get code to do sorts, shuffles, max, min, and binarySearch. This is best demo'ed in the example below:

Proto-Type | Description
static int binarySearch(List list, Object key) | Searches the specified list for the specified object using the binary search algorithm.
static Object max(Collection coll) | Returns the maximum element of the given collection, according to the natural ordering of its elements.
static Object min(Collection coll) | Returns the minimum element of the given collection, according to the natural ordering of its elements.
static void reverse(List l) | Reverses the order of the elements in the specified list.
static void shuffle(List list) | Randomly permutes the specified list using a default source of randomness.
static void sort(List list) | Sorts the specified list into ascending order, according to the natural ordering of its elements.
static List synchronizedList(List list) | Returns a synchronized (thread-safe) list backed by the specified list.
static List unmodifiableList(List list) | Returns an unmodifiable view of the specified list.

TryList2.java


import tools.*;
import java.util.*;
class TryList2
{
    List store = new ArrayList();
    void load(String file)
    {
        String str;
        MyInput in = new MyInput(file);
        do
        {
            str = in.get();
            if (str != null)
            {
                str = str.trim();
                store.add(str);
            }

        }while (str != null);
        System.out.println(store);
    }
    void doCmd(MyInput input, String str)
    {
      int index;

      if (str.equals("load"))
            {
                System.out.println("Enter filename to load");
                str = input.get();
                load(str);
            }
      else if (str.equals("toString"))
                System.out.println(store);
      else if (str.equals("sort"))
            {
                Collections.sort(store);
                System.out.println(store);
            }
      else if (str.equals("shuffle"))
            {
                Collections.shuffle(store);
                System.out.println(store);
            }
      else if (str.equals("reverse"))
            {
                Collections.reverse(store);
                System.out.println(store);
            }
      else if (str.equals("max"))
            {
                str = (String)Collections.max(store);
                System.out.println("max = " + str);
            }
      else if (str.equals("min"))
            {
                str = (String)Collections.min(store);
                System.out.println("min = " + str);
            }
      else if (str.equals("binarySearch"))
            {
                System.out.println("search value ?");
                str = input.get();
                index = Collections.binarySearch(store, str);
                System.out.println("binarySearch index = " + index);
            }
      else System.out.println("Illegal command");
    }
    public static void main(String[] args)
    {
        TryList2 doit = new TryList2();
        String str;
        System.out.println("anyone home??");

        MyInput input = new MyInput();
        do
        {
            System.out.println(" **********************************");
            System.out.println("enter load, toString, sort, shuffle, max, min,   ");
            System.out.println("reverse, binarySearch");
            System.out.println(" -----------------------");
            str = input.get();
            str = str.trim();

            doit.doCmd(input, str);
        } while (str != null);
    }


}


class ArrayList implements List

So far all of the examples have used ArrayList. The ArrayList matches the List interface pretty closely. There are a few extra methods in ArrayList, but no major deviation from the concept of a List. An ArrayList is meant to feel like an Array that dynamically grows. An ArrayList is good if you want to randomly access or set entries in the list with the get(index) or set(index, object) methods.

class Vector implements List

The Vector class was introduced in Java in the 1.1 version. In 1.2, java was reworked to have a more symetric and cleaner interface to work with more collection class types.

The ArrayList is almost the same as the Vector class. One difference is that by default the Vector class is synchronized (we will cover this concept when we cover Threads) and the ArrayList is not. This means that by default the Vector class will work with multiple tasks accessing at the same time. However, this also means that the ArrayList is more efficient because it doesn't have the synchronization overhead. The Vector class was defined in 1.1 to be synchronized, so for backwards compatibility it has to stay that way in later releases.

If you really want a synchronized ArrayList, you can get it by invoking the synchronizedList method in the Collections class. This is the best of both worlds for ArrayList ---- run faster by default and add on synchronization when you really need it.

The Vector class has multiple names for a lot of the common functions. This is also for backwards compatibility. The old names will probably phase out in favor of the newer names. Here is a small list of the duplicate names:

- addElement - new name is add
- elementAt - new name is get
- insertElementAt, new name is add --- the version with an index
- removeElement - new name is remove
- setElementAt - new name is set

When you see an example using the Vector class and one of the methods, its probably because the example was created in 1.1 and hasn't been migrated forward. The other reason, it might be still around is because it runs as a Java Applet, and most browsers haven't upgraded to the newer Java --- I.E., and Netscape 4.xxx are on 1.1.x. Netscape 6 is now running Java 1.3.x

class LinkedList implements List

A LinkedList is not as good as an ArrayList for random access, but is a lot better if you are creating linked lists and you need to insert into the middle of the list. The ArrayList on the other hand is somewhat inefficient for inserting into the middle of the list. Because LinkedLists are often used to implement Queues, accessing or modifying the head or the tail of the Queue is important. You can see this by looking at the following table which includes the extra methods available for LinkedList that go beyond the required List interface.

Proto-Type | Description
void addFirst(Object o) | Inserts the given element at the beginning of this list.
void addLast(Object o) | Appends the given element to the end of this list.
Object getFirst() | Returns the first element in this list.
Object getLast() | Returns the last element in this list.
Object removeFirst() | Removes and returns the first element from this list.
Object removeLast() | Removes and returns the last element from this list.

Using More Complicated Objects

I have kept it as simple as possible by using the String class for all of my stored Objects. This avoids some complicated issues.

A couple of issues to consider when you create your own object to store in a collection.

- When you pull the object out of the collection using a get method or an iterator, you will get something of type Object. This normally will need to be caste if you want to use your classes methods. If the object doesn't work with the Caste, you get an exception. Note the attempt to add a Cat to my collection of Dogs.
- Some of the methods in the collections classes assume certain methods are available in your Class. It's a good idea to override the toString in your class, if you want to print the collection like :
System.out.println(dogs);
- If you want methods like contains to work, your object will need to have a valid equals method ---- see comments in the example below.

Dogs.java


import java.util.*;
class Cat{
  private String name;
  Cat(String n)
  {
    name = n;
  }
  public String toString(){
  return name;
  }
}

class Dog {
   int number =1;
   String name;
Dog(String n) {
      name = n;
   }
Dog(String n, int num) {
      name = n;
      number = num;
   }
public String toString() {
   return name + ":" + number;
   }
void print ()
    {
        System.out.println("dog: " + toString());
    }

/* COMMENTED OUT CODE *******************************
public boolean equals(Object obj)
    {
        boolean retval = false;
        if (obj instanceof Dog)
        {
            Dog d = (Dog)obj;
            if (d.number == number && name.equals(d.name))
                return true;
        }
        return false;
    }
**************************************** END OF COMMENTED OUT CODE */
}
// -----------------------------------------------

public class Dogs {
public static void main(String[] args) {
      Vector dogs = new Vector();
      Dog d;
      Object ob;

      dogs.add(  new Dog("Tiger") );
      dogs.add(  new Dog("Fido")  );
      dogs.add(  new Dog("Maya")  );
      dogs.add(  new Dog("Benji") );

      // After trying this once, uncomment the equals method in Dog
      // recompile and rerun and see the difference.
      d = new Dog("Fido");
      if (dogs.contains(d))
        {
          System.out.println(" We already have a " + d);
          d = new Dog("Fido", 2);
          dogs.add(d);
        }
      else
        {
            System.out.println("We don't have " + d + "  Adding ...");
            dogs.add(d);
        }

      System.out.println("********** Looking at my dogs ************");
      Iterator e = dogs.iterator();
      while(e.hasNext())
      {
      // Notice the Caste which is required to call print
          d = (Dog)e.next();
          d.print();
      }


      // What happens with the following statement
      dogs.add  (new Cat("Shelly") );

      System.out.println("Here is my collection :");
      // The following requires you to override toString in the Dog and Cat
      // classes to get something meaningful
      System.out.println(dogs);

      System.out.println("*********** Looking at my cat and dogs ******");
      e = dogs.iterator();
      while(e.hasNext())
      {
          // No Caste needed here, because Object is just fine
          // println will automatically call toString on the Object class
          // Note that this works for Dog and Cat -- both can be Object
          ob = e.next();
          System.out.println(ob);
      }

      System.out.println("****Using print to Look at my cat and dogs ******");
      e = dogs.iterator();
      while(e.hasNext())
      {
        // This compiles, but .....
        // Caught red-handed at Run-Time trying to
        // convert our Cat to a Dog.
        // System will throw an exception

          d = (Dog)e.next();
          d.print();
      }
  }

}



Type Safe Collections

Maybe you want to prevent your Dog Collection from being polluted with something as impure as a Cat. You can fix the problem by creating your own collection class. In the previous Dogs.java program the Dogs class "has a" collection class (Vector).

- Now Dogs will be derived from another collection class (I could pick Vector again, but I decided to mix it up for fun, so I chose ArrayList). So the new relationship is: Dogs "is an" ArrayList.
- Now I can override the add method and make sure that no Cat can enter my Dog collection.
- Brimming with confidence, we now decide to sort our collection of Dogs. But OOPs we hit another snag that we have to fix in the next example.

Dogs2.java


import java.util.*;
class Cat{
  private String name;
  Cat(String n)
  {
    name = n;
  }
  public String toString(){
  return name;
  }
}

class Dog {
   int number =1;
   String name;
Dog(String n) {
      name = n;
   }
Dog(String n, int num) {
      name = n;
      number = num;
   }
public String toString() {
   return name + ":" + number;
   }
void print ()
    {
        System.out.println("dog: " + toString());
    }
public boolean equals(Object obj)
    {
        boolean retval = false;
        if (obj instanceof Dog)
        {
            Dog d = (Dog)obj;
            if (d.number == number && name.equals(d.name))
                return true;
        }
        return false;
    }
}
// -----------------------------------------------

public class Dogs2 extends ArrayList {

// Overridden method
public boolean add(Object o)
{
    Class cl;
    if (o instanceof Dog)
        return super.add(o);
    // cute trick to find out the actual name
    // of class that you have:
    cl = o.getClass();
    System.out.println("I wanted a Dog and you gave me a " +
            cl.getName());
    return false;
}
public static void main(String[] args) {
      Dogs2 dogs = new Dogs2();
      Dog d;
      Object ob;

      dogs.add(  new Dog("Tiger") );
      dogs.add(  new Dog("Fido")  );
      dogs.add(  new Dog("Maya")  );
      dogs.add(  new Dog("Benji") );

      // What happens with the following statement
      dogs.add  (new Cat("Shelly") );

      System.out.println("****Using print to Look at my dogs ******");
      System.out.println("---- Guaranteed Dog instances ----");
      Iterator e = dogs.iterator();
      while(e.hasNext())
      {
          d = (Dog)e.next();
          d.print();
      }

      System.out.println("****** Now Onto Sorting my Dogs");
      Collections.sort(dogs);
      System.out.println("Sorted Dogs:");
      System.out.println(dogs);
  }

}



Comparable Interface to fix sort

If you want to sort, use binarySearch , max, min or any other method that needs to be aware of how to compare objects, you will run into the problem described above. The solution is to have our Dog class implement the Comparable interface. This means that we need to add a method called compareTo, which returns 0 if the 2 objects match and positive or negative depending on which object is larger. The reason we didn't have this problem earlier with inserting Strings into our Collections is because the String class already implements Comparable.

Dogs3.java


import java.util.*;
class Dog implements Comparable {
   int number =1;
   String name;
Dog(String n) {
      name = n;
   }
Dog(String n, int num) {
      name = n;
      number = num;
   }
public String toString() {
   return name + ":" + number;
   }
public int compareTo(Object o)
{
    // A good chance I will always get a real Dog here
    // if people use my Type-Safe Dogs3 Collection class
    // It's still possible to call compareTo with a Cat,
    // so maybe I should add the paranoid code.
    // But what can I do if I discover a problem anyway ????
    // About the only thing I can do is throw an exception like
    // ClassCastException and that's what I get anyway just doing
    // the caste.
    // I'm sure you wanted to hear my rambling explaination here :-)

    Dog d = (Dog)o;
    int value = name.compareTo(d.name);
    if (value != 0) return value;
    // For ties on the name, break the tie with the number
    return (number - d.number);
}
void print ()
    {
        System.out.println("dog: " + toString());
    }
public boolean equals(Object obj)
    {
        boolean retval = false;
        if (obj instanceof Dog)
        {
            Dog d = (Dog)obj;
            if (d.number == number && name.equals(d.name))
                return true;
        }
        return false;
    }
}
// -----------------------------------------------

public class Dogs3 extends ArrayList {
public boolean add(Object o)
{
    Class cl;
    if (o instanceof Dog)
        return super.add(o);
    cl = o.getClass();
    System.out.println("I wanted a Dog and you gave me a " +
            cl.getName());
    return false;
}
public static void main(String[] args) {
      Dogs2 dogs = new Dogs2();
      Dog d;
      Object ob;

      dogs.add(  new Dog("Tiger") );
      dogs.add(  new Dog("Fido")  );
      dogs.add(  new Dog("Maya")  );
      dogs.add(  new Dog("Benji") );

      dogs.add(  new Dog("Tiger", 2) );
      dogs.add(  new Dog("Tiger", 3) );


      System.out.println("****Using print to Look at my dogs ******");
      System.out.println("---- Guaranteed Dog instances ----");
      Iterator e = dogs.iterator();
      while(e.hasNext())
      {
          d = (Dog)e.next();
          d.print();
      }

      System.out.println("****** Now Onto Sorting my Dogs");
      // If you read the Online help system, you will find out
      // that Collections.sort can only sort classes that implement
      // the Comparable interface which contains the method compareTo
      // Note that we added this to our Dog class, and now it works

      Collections.sort(dogs);
      System.out.println("Sorted Dogs:");
      System.out.println(dogs);
  }

}



Exercise

LinkedList Problem

1. Create a class called StudentRecord that contains a students records in a given class. Your StudentRecord class should contain fields for Student_Number, Name, and an array of 3 test scores.
2. Your StudentRecord class should override the toString() method to write out the information for each student record.
3. Create another class called ClassList which contains a LinkedList object holding StudentRecord objects.
4. Make sure your ClassList class has a method for adding a new StudentRecord object to your ClassList. Choose the calling sequence to this method to be convenient for you.
5. Add another method to your ClassList that looks up a student's name in the LinkedList and prints out the appropriate record for this student.
6. Add a print_all method to your ClassList that outputs the information for all of your StudentRecords. This method should use an Iterator. Part of the output for each student should be his average test score.
7. Create a file with each line of input containing information about one student. Read in the file with MyInput or any other I/O technique. The StringTokenizer will be useful to you to parse the individual fields for each student.
Your code should have a structure something like the following:


// You will need an import statement here

class StudentRecord{
  int Student_Number;
  String Name;
  int tests[] = new int[3];
  int testAverage(){
  	// return the average of the tests scores
  }
  public String toString(){
// print contents of StudentRecord  -- fill in code
    }
}

class ClassList {
	// Some LinkedList declaration
  void addStudent(int Student_Number, String Name, ....){
	}
  void print_all(){
	// Use an iterator to print all StudentRecords in ClassList
	}
  void find_and_print(String name_to_find){

	}
  public static void main(String args[]){
	// Read in data from a file.  Each line is a new record, and use
	// the StringTokenizer to parse out the columns
	}


}


Create a simple class called Marriage which keeps track of husband/wife pairs. Using the Marriage class update some of the above java programs to store Collections of Marriages.

1. Update TryCollection.java
2. Update TryList.java
3. Update TryList2.java

Last Updated: October 29, 2003 12:53 PM