站内搜索: 请输入搜索关键词
当前页面: 在线文档首页 > Java Tutorial 5.0 英文版

Inner Classes - Java Tutorial 5.0 英文版

The JavaTM Tutorial
Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Trail: Learning the Java Language
Lesson: Classes and Inheritance

Inner Classes

To help you get a handle on inner classes and what they are good for, let's revisit the Stack class. Suppose that you want to add to this class a feature that lets another class enumerate the elements in the stack, using the java.util.Iterator interface. This interface contains three method declarations:
public boolean hasNext();
public <E> next();
public void remove();
Iterator defines the interface for stepping once through the elements within an ordered set in order. You use it like this:
while (hasNext()) {
    E element = next();  //do something with element
}

Note: The Iterator interface and the ArrayList class use generic types. To be as general as possible, this example is parameterized with Object. If generics are unfamiliar to you, see Generics (in the Learning the Java Language trail)
The Stack class itself should not implement the Iterator interface, because of certain limitations imposed by the API of the Iterator interface: two separate objects could not enumerate the items in the Stack concurrently, because there's no way of knowing who's calling the next method; the enumeration could not be restarted, because the Iterator interface doesn't have methods to support that; and the enumeration could be invoked only once, because the Iterator interface doesn't have methods for going back to the beginning. Instead, a helper class should do the work for Stack.

The helper class must have access to the Stack's elements and also must be able to access them directly because the Stack's public interface supports only LIFO access. This is where inner classes come in.

Here's a Stack implementation that defines a helper class, called StackIterator, for enumerating the stack's elements:

public class Stack {
    private ArrayList<Object> items;

    //code for Stack's methods and constructors
    //not shown

    public Iterator<Object> iterator() {
        return new StackIterator();
    }
    private class StackIterator implements Iterator {
        int currentItem = items.size() - 1;

        public boolean hasNext() {
            ...
        }
        public ArrayList<Object> next() {
            ...
        }
        public void remove() {
            ...
        }
    }
}
Note that the StackIterator class refers directly to Stack's items instance variable.

Inner classes are used primarily to implement helper classes like the one shown in this example. If you plan on handling user-interface events, you'll need to know about using inner classes because the event-handling mechanism makes extensive use of them.

You can declare an inner class without naming it, called an anonymous class. Here's yet another version of the Stack class, in this case using an anonymous class for its iterator:

public class Stack {
    private ArrayList<Object> items;

    //code for Stack's methods and constructors
    //not shown

    public Iterator<Object> iterator() {
        return new Iterator<Object>() {
            int currentItem = items.size() - 1;
            public boolean hasNext() {
                ...
            }
            public ArrayList<Object> next() {
                ...
            }
            public void remove() {
                ...
            }
        };
    }
}
An anonymous class is generally used inside an expression and it does not have member scope, since it isn't visible to the enclosing class. Anonymous classes can make code difficult to read. You should limit their use to those classes that are very small (no more than a method or two) and whose use is well understood, such as event-handling classes.

If you want to use an anonymous inner class, but it's too long to include inline, you can use a local class. A local class is like a named anonymous class. Typically, a local class is declared within a method or to initialize a field and, like an anonymous class, it also does not have member scope. For example, using the Stack example, the StackIterator class could be implemented as a local class inside the iterator method, like this:

public class Stack {
    private ArrayList<Object> items;

    //code for Stack's methods and constructors
    //not shown

    public Iterator<Object> iterator() {
        private class StackIterator implements Iterator<Object> {
            int currentItem = items.size() - 1;

            public boolean hasNext() {
                ...
            }
            public ArrayList<Object> next() {
                ...
            }
            public void remove() {
                ...
            }
        }
        return new StackIterator();
    }
}

Other Facts about Nested Classes

Like other classes, nested classes can be declared abstract or final. The meaning of these two modifiers for nested classes is the same as for other classes. Also, you may use the access specifiers — private, public, and protected — to restrict access to nested classes, just as you do to other class members.

Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Copyright 1995-2005 Sun Microsystems, Inc. All rights reserved.