Inner classes often throw the junior or entry-level Java programmer for a loop for a variety of reasons. Not the least of which is the confusing, usually misused nomenclature. Here's a rundown of the four types of inner classes and the officially correct name to use for each:

  • Nested (static) Top-level Classes
    Inner classes that are declared static in a containing class. They behave just like ordinary (non-inner) top-level classes in the package. The nesting of top-level classes in this way is really only a matter of logical organization. Here is an example of a nested top-level class:
    public class Task {
        static class Schedule {
            public long getTimeToNextRun() {
                ...
            }
            public void reset() {
                ...
            }
        }
        ...
    }
    The important difference between nested top-level classes and member classes is that these are not internally associated with instances of the containing class. Thus, nested top-level classes do not have access to the non-public fields and methods of the containing class.

  • Member Classes
    Inner classes that are declared just like other members (instance variables and methods) of a containing class. Each Instance of a member class is implicitly associated with an instance of the containing class, and has access to all fields and methods of the containing instance, even private ones. The link from the member class instance and the containing object is automatic and internal - your code does not have to do anything to implement it. Here is an example of a member class:
    public class LinkedList {
        private class ListIter implements Iterator {
            public boolean hasNext() {
                ...
            }
            ...
        }
    }
  • Local Classes
    Inner classes that are declared within a block of Java code, not as members of the containing class. Local classes relate to member classes in the same way that local variables relate to instance variables. They can be thought of as "members" of the containing code block, as they are in scope only within that block. Local classes have names and have declaration syntax just like member classes. Here is an example:
    protected void setup(final Object someUsefulObject) {
        Foo eventSource = getFoo();
        class LocalListener implements FooListener {
            public void eventFired(FooEvent event) {
                someUsefulObject.doSomething();
            }
        }
    
        eventSource.addListener(new LocalListener());
    }
    Note that the method argument is declared final. This is because local classes can only access variables of the containing code block if they are final. The explanation of the reasoning behind this limitation is a little too involved for me to undertake right now - do some Googling and find out for yourself. :-P

  • Anonymous Inner Classes
    A local class that is declared without a name. Basically, using an anonymous class is equivalent to declaring a (named) local class and instantiating it, but it is done in one syntactical step. This is accomplished through a special use of the new operator., making the declaration/use of an anonymous class a type of Java expression (as opposed to a statement). It is probably easier to understand through an example:
    protected void setup(final Object someUsefulObject) {
        Foo eventSource = getFoo();
        eventSource.addListener(new FooListener() {
                public void eventFired(FooEvent event) {
                    someUsefulObject.doSomething();
                }
            });
    }
    I think you can see the similarity between the local class example and this anonymous class, as well as how much more concise and compact the anonymous class example is. However, it is a mistake to always consider "concise" and "compact" with "better" - often the more verbose code is more readable and easier to understand quickly, and thus better for the long-term. In this contrived example it may not seem much of a difference, but in real code I usually prefer readability over compactness.

When Your Privates Aren't Really Private
Well, your privates (or, more accurately, some of your class' privates - it's "private" inner classes) are not really private. That's because the Java Virtual Machine does not see member classes with the same visibility as you declare them. While they can be declared as private or protected in source code (as well as public and "package"), the VM at runtime interprets them differently: protected classes are treated as public and private ones as "package" (no visibility modifier). This is because when inner classes were introduced with JDK 1.1, only the compiler was changed to accommodate them, not the VM. Member classes are compiled to ordinary class files, only with funny names; therefore they can only really have public and package visibility since those are the only qualifiers recognized by the virtual machine specification.

Even though "private" or "protected" information is not used by the virtual machine at runtime, the compiled class files (byte code) do indicate the visibility that was declared in the source; a compliant compiler will enforce the desired restrictions at compile time [Java In A Nutshell, 2nd Edition].
Sure, this information isn't likely to provide you much help on your next distributed transactional, multi-tier business process automation application. But hey, trivia is still interesting to a lot of people - Jeopardy! has been popular for years based on that premise. So take this bit of trivia as worth what you paid for it, if nothing else.    :-P

line
All photographs and content is copyright © 2003-2006 Eric Rizzo & Jazmine Rizzo

contact classes office hours about me Go home