|
|
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
|