Ray's CSC324H Tutorial Pages


Interfaces and Member Classes

Topics

Other references

Source code


Interfaces

To recap, the Enumeration interface has two methods:

Suppose we have a class called StringList, a list for strings that uses a linked data structure (composed of StringNode's) to store the data.

class StringNode
{
	String element;
	StringNode next;

	StringNode(String element, StringNode next)
	{
		this.element = element;
		this.next = next;
	}
}

public class StringList
{
	StringNode front;

	public void addToFront(String s)
	{
		StringNode newFront = new StringNode(s, front);
		front = newFront;
	}

	public Enumeration elements()
	{
		/* ??? */
	}
}

We want to implement a method in StringList called elements() that returns an Enumeration of the Strings inside the list.

An easy thing to do would be to add all of the String's to a Vector and then return the Enumeration returned by the Vector's elements() method. But this requires the overhead of creating a Vector, so it's not desirable.

We can create our own Enumeration without much trouble. Call it StringListEnumerator. This class has two members: "list", which is the list to traverse, and "current", a marker for the current element in the Enumeration.

class StringListEnumerator implements Enumeration
{
	private StringList list;
	private StringNode current;

	/* ... */
}

When the StringListEnumerator is first created, we must tell it what list to traverse, so we require such a parameter in the constructor. Since the traversal starts at the beginning of this list, we make "current" refer to the same node as "front".

public StringListEnumerator(StringList list)
{
	this.list = list;
	current = list.front;
}

If there are no elements to traverse, then "current = null".

public boolean hasMoreElements() { return (current != null); }

But when there are elements to traverse, we advance the "current" marker by making it refer to the node "next" to it. (If this can't be done, we throw an exception.)

public Object nextElement()
{
	if (current == null) 
		throw new NoSuchElementException("StringList");

	Object value = current.element;
	current = current.next;
	return value;
}

So we can complete our elements() method:

public class StringList
{
	StringNode front;

	public void addToFront(String s)
	{
		StringNode newFront = new StringNode(s, front);
		front = newFront;
	}

	public Enumeration elements()
	{
		return new StringListEnumerator(this);
	}
}

Member classes

Because the StringListEnumerator has package visibility, it seems that any class in the same package might find StringListEnumerator useful. This is highly unlikely. It would be great if we could portray that StringListEnumerators are relevant only to StringLists. We can do this be creating a member class.

public class StringList
{
    StringNode front;
    
    public void addToFront(String s)
    {
        StringNode newFront = new StringNode(s, front);
        front = newFront;
    }
    
    public Enumeration elements()
    {
        return new Enumerator();
    }

    private class Enumerator implements Enumeration
    {
        // the list to traverse is "this" list, so there
        // is no "list" reference
        
        private StringNode current;

        public Enumerator()
        {
            current = front;
        }
        
        public boolean hasMoreElements() { return (current != null); }
        
        public Object nextElement()
        {
            if (current == null) 
                throw new NoSuchElementException("StringList");

            Object value = current.element;
            current = current.next;
            return value;
        }
    }
}

We replace StringListEnumerator with a class Enumerator that is a inside StringList; it is a member class. Because Enumerator is a member class, it has access to the internal variables of its containing class StringList, even those marked private.

That is why the constructor doesn't have to take a parameter anymore. Before, the StringListEnumerator had to be told which StringList it was traversing. Now that we've identified the enumerator as a member of StringList, it can just traverse the StringList object that contains it.

The other thing to note is that we make Enumerator private so that other classes can't access it. Thus, only StringList can instantiate it, which is what we really want.

Note: When you compile the .class files, the byte-code for the Enumerator class will appear inside a file called StringList$Enumerator.class. This is Java's way of identifying through the file system that Enumerator is a class within StringList.


Main CSC324H Home Page | Ray's CSC324H Home Page

This page is maintained by Ray Ortigas, a teaching assistant for CSC324H - Principles of Programming Languages at the Department of Computer Science, University of Toronto. If you have any questions or comments about this page, please send e-mail to Ray at rayo@cs.toronto.edu.

Last updated March 21, 1999 18:04.