Inner Classes and "Shtuff"
Index
1. Introduction
2. History and Basic Facts of Inner Classes in Java
3. Four Types of Inner Classes
3.1 Nested Inner Classes (static member classes)
3.2 Inner Classes (member classes)
3.3 Local Inner Classes
3.4 Anonymous Inner Classes
4. Advantages of Using Inner Classes
4.1 Blocks of Code
4.2 Integration of Objects in Objects
4.3 More Object-Oriented Structure
5. Inner Class Uses and Strategies
5.1 Callbacks
5.2 Inner Class Strategy, Data Access Objects (DAO)’s
6. Summary
7. References
Introduction
Inner classes are a very useful concept in the java
language. They can help to keep code cleaner, they can help to control access
to objects and they provide a certain since of robustness in code that aids in
object oriented design.
This paper will address the history of the inner class as it figures into the Java language. We will also discuss the various kinds of inner classes, their names, how many and what types of files are generated by the compiler, access restrictions and why the restrictions are what they are. We will then discuss some examples and purposes for inner classes in the development world.
History and Basic Facts of Inner Classes in Java
Up until Jdk 1.1, the java language only supported top-level classes. At the introduction of jdk1.1 Sun introduced the concept of nested/inner classes in java. This allowed a developer to use inner classes as some sort of swiss army knife—they can be used to do many different things, and can be used to reproduce some C++ features that are otherwise unavailable in Java. This java feature of inner classes is limited to the compiler. To compile code that contains inner classes you will need jdk1.1 or later, BUT because of the way the class files are generated during compilation, the compiled code can be executed on any jvm. The naming of anonymous inner classes varies from one compiler implementation to another. Sun uses numbers to provide anonymous class names. For instance, if a top-level class was named Car and one of the methods contained an anonymous inner class, that class might be named Car$1.class by the compiler.
As far as the java interpreter is concerned, there is no such thing as an inner class: all classes are normal top-level classes. There are three types of inner classes and will be discussed shortly but they are: member classes – static and non-static or ‘nested inner’ and just plain ‘inner’ classes. To make this ‘magic’ work the compile performs various ‘tricks’ that can be viewed by using the javap disassembler on the generated class files. Once disassembled it can be seen that the compiler actually inserts hidden fields, methods, and constructor arguments into the classes it generates. This information will be used to help explain the various behaviors by each type of inner class. It should also be known that a file can only contain one outer public class. Any attempt to create a file with more than one public class will cause the compiler to yell. A file can contain multiple non-public classes (inner classes) though.
Four Types of Inner Classes
When referring to inner classes we will make a reference to the containing class. This containing class is usually referred to as a/the top-level class. A top-level class is a class that is defined as a member of a package. In general, inner classes make it easier for a developer to connect objects together, since classes can be defined closer to other objects. They are classes defined from within the same java file. They are ‘contained’ inside a ‘container’ class or a ‘top-level’ class.
There are three types of inner classes. But, if we consider a static inner class then there are four. The first type of inner class we will discuss is the nested inner class or static member class (because it is a member of the top-level class). We will then go on to discuss the inner classes or plain old member classes of which these classes are instance classes of the top-level class in which it is contained. We will then discuss local inner classes, which are defined inside of a block of code or more generally a method perhaps. Finally, we will briefly discuss the anonymous inner class.
Nested Inner Classes (static member classes)
Nested inner classes are classes within classes. A nested
inner class has the same behavior as any static member of a class. You can
access it without initializing the parent class, and they can access the parent
class’s static methods and variables, even if the variable is private. These
types of inner classes are always defined with the keyword ‘static’. An access
tag (public, protected, private) can be defined, but by default a nested class
takes the default package access. This produces an interesting question: if the
effect of marking it as static means there is only one instance of any
variables, no matter how many instances of the outer class are created, how
could the static inner class know which variables to access of its non-static
outer class? The answer is obvious, and it is that it could not know, which is
why a static inner class cannot access instance variables of its enclosing
class. Sun considers nested classes to be top-level classes. Since the static
member class is compiled into an ordinary top-level class, however, there is no
way it can directly access the private members of its container. As mentioned
above in the history section, the compiler will generate extra code. This makes
since, because if a static member class uses a private member of its containing
class (or vice versa), the compiler automatically generates non-private access
methods and converts the expressions that access the private members into
expressions that access these specially generated methods. These generated
methods are given the default package access, which is sufficient, as the
member class and its containing class are guaranteed to be in the same package.
Compiled nested inner classes are named as “OuterClassName$InnerClassName.class”.
Where “OuterClassName” is the name for the container class (or
package) and “InnerClassName” is the name of the
static nested inner class defined inside of the containing class. The $ in this
name is automatically inserted by the compiler. So, if you were to create a
class OuterClass.java and within that class a class named “InnerClass”, the
compiler will generate two class files. This is why inner classes can be run
from any JVM (as mentioned above). Since, by definition, a nested inner class
is static it can be accessed from anywhere in your code by using “OuterClass.InnerClass”. The same applies to
writing import statements.
Inner Classes (member classes)
These ‘member classes’ are implemented much like a static
member class. They get compiled into separate top-level class files and the
compiler performs various code ‘tweaks’ to get it to work. Inner classes differ
from a nested class because they do not have a static tag to them. Therefore,
every instance of an inner class requires an instance of the container class,
and the container class can have multiple instances of the contained
class/inner class. The compiler enforces this association by defining a
synthetic field named this$0 in each member class. This field is used to hold a
reference to the enclosed instance. Every inner class (non-static) constructor
is given an extra parameter that initializes this field.
A non-static inner class can be declared public, protected,
or private or given the default package visibility, but as mentioned
previously, member classes are compiled to top-level class files, but top-level
classes can only have public or package access, which means member classes can
only have public or package visibility (to the Java interpreter). So, if a
member class is declared as protected it is treated as a public class and if it
is declared as private it has package visibility. According to anonymous,
“Although the interpreter cannot enforce these access control modifiers, the
modifiers are noted in the class file. This allows any conforming Java compiler
to enforce the access modifiers and prevent the member classes from being
accessed in unintended ways.” Just a thought but can you deduce how this
relates in a security centric way?
Local Inner Classes
These types of inner classes are defined inside a block of
code, such as a method and are not available outside of the method in which it
is defined, even inside class outer. However, like member classes, a local
class can refer to fields and methods in its containing class for the same
reason and mechanism available to a member class; it is passed a hidden
reference to the containing class in its constructor and saves that reference
away in a private field added by the compiler. Also, the private fields and
methods of the container class are also available to local inner classes
because the compiler will insert any required accessor methods. What separates
a local class from a member class is the ability to refer to local variables in
the scope that defines them. There is, hence, one restriction to this: local
classes can only reference local variables and parameters that are declared
final. According to the Java spec, this is because the compiler automatically
gives the local class a private instance field to hold a copy of each local variable
the class uses and as previously mentioned the compiler will add special hidden
parameters to each local class constructor to initialize the compiler created
private fields. Therefore, a local class isn’t accessing local variables but
merely copies, albeit private copies, of them. And to make this work a
guarantee must be in place that says these values won’t change and that is by
using the keyword final. Almost magic!
Anonymous Inner Classes
An anonymous inner class usually does not have a name. They
are often used during GUI development to implement listeners. An anonymous
class must either extend a class or implement an interface, but it can’t do
both like a member class. An access modifier is never specified and cannot be
specified. Since the class doesn’t have a name, it doesn’t have a constructor.
By now the reader should have a pretty good understanding of
inner classes and how they are created via the compiler and how they are
interpreted by the interpreter and how and why their access behavior exists. Next,
we will touch on some basic advantages to using inner classes.
Advantages of Using Inner Classes
There are quite a few advantages to using inner classes.
These advantages include, but are not limited to:
·
blocks of code,
·
integration of objects within objects, and
·
enabling a more object-oriented structure.
Blocks of Code
Nested inner classes give developers the ability to
implement blocks of code that can be used to realize special functions inside a
given object. Using nested inner classes a developer can integrate blocks of
code inside an object to perform special tasks pretty much like method pointers
in C.
Integration of Objects in Objects
By providing developers a mechanism for integrating blocks
of code inside other objects via an inner class, a developer can integrate
objects in objects which can lead to a more object-oriented design. A developer
can create objects that are specific to the enclosing class. This makes the
code easier to read (readability) and to maintain (maintainability) and leads
to a more object-oriented design.
More Object-Oriented Structure
By allowing developers to define inner objects top-level
nested classes can be defined inside another object. Multiple class files do
not need to be created for every distinct object in the program. Objects can be
integrated into one another, which makes the code easier to understand and
makes since, from an object-oriented perspective, to have classes only used by
a certain class inside of that class.
Inner Class Uses and Strategies
There are many uses and strategies implemented that take
advantage of the powerful nature of inner class design. We will present two of
these approaches. The first approach is in the implementation of a callback.
Java doesn’t necessarily use callbacks in the way that callbacks are defined in
the C programming language, but they can certainly be imitated as is
implemented in the JAVA AWT framework. The second approach is merely a design
strategy applied by various persistence frameworks.
Callbacks
A common technique in the C language is to pass a pointer to
a function in the argument list of another function. The receiving function can
invoke the passed in function using the pointer. This approach is referred to
as a callback. Callbacks are very useful in situations where you want to invoke
different functions without needing to know what function is being invoked. For
example, a plotting function could receive a pointer to a function that takes a
value on the horizontal axis as an argument and returns a value for the
vertical axis. The plotting function could then plot any such function that is passed
to it. Inner classes are very useful when you want to implement callbacks.
Java, however, does not provide pointers (direct memory addresses) to methods.
Instead, interfaces are used for callbacks. In this case, a method holds an
interface reference in its argument list and then invokes a method in the
interface. A callback method is a method intended to be passed as a parameter.
The callee can then call the passed in method asynchronously and with whatever
parameters it deems appropriate.
One of the basic techniques used in java to fake a call back
is to 1) use inner classes to define an anonymous callback class, 2) instantiate
an anonymous callback delegate object, and 3) pass it as a parameter all in one
line. This allows a developer to efficiently have a separate block of code to
handle the actionPeformed
function of the Actionlistener
interface for every graphical component object. This is one of the many
features found in other languages that the JAVA language also provides.
Inner Class Strategy, Data Access Objects (DAO)’s
Let’s say a developer wants to isolate data access and
manipulation in a separate layer, while also keeping member variables private
and hence retaining full encapsulation and object integrity. How do we handle
this?
A Data Access Object (DAO) is found when dealing with
object-relational persistence. The DAO is the primary object of the ‘Data
Access Object’, one of the core J2EE patterns. A DAO abstracts the underlying
data access implementation for the BusinessObject to enable transparent access
to the data source. There is often a need for the DAO implementation to modify
data on the domain object (Business Object) that is being persisted. For
instance, when a new object is being inserted into a relational database table,
it can sometimes be auto-assigned a surrogate primary key as opposed to a
natural primary key. In a properly designed entity class, the field
representing the primary key should not be modifiable to the public, as this
would compromise the integrity of the object’s state. A solution to this is to
create the DAO interface as an abstract static inner class of the domain object
to be persisted. This is a viable solution because inner classes have access to
the private members of the outer class. This allows the DAO implementation to
have access to select private members, while still isolating the actual
persistence behavior in its own class. For instance, the Customer class has
three private members: name, customerNumber (natural primary key) and
customerId ( auto generated surrogate primary key). We want to make sure the
customerId cannot be changed outside of the Customer class (the business
object). So, to satisfy this requirement we implement the CustomerDAO as an
abstract inner class of the Customer class. In this example, the customerId is
available only as a readable property to the public while retaining
encapsulation and guaranteeing no change while the DAO implementation is
allowed to modify the attribute.
Summary
In this paper we have discussed inner classes as they are applied in java. We have discussed the history and basic ideas behind inner classes. We have also discussed the various types of inner classes, the nested-static inner class the non-static inner class, the local inner class and the anonymous inner class. We discussed how inner classes are invoked, their scope and how they relate to the java compiler and interpreter. We also discussed some concepts and design practices that currently use the inner class design, such as the implementation of ‘callbacks’ and its use in persistence frameworks.
References
http://mindprod.com/jgloss/callback.html
http://www.javaworld.com/javaworld/javatips/jw-javatip10.htmll
http://java.about.com/cs/javadocumentation/g/callback.html
http://www.particle.kth.se/~lindsey/JavaCourse/Book/Part1/Java/Chapter04/interface.html
http://nils.kilden-pedersen.net/DAO_pattern/InnerClassStrategy.html
http://www.unix.org.ua/orelly/java-ent/jnuy/ch03_13.htn