Inner classes | CodeGuru

Inner classes

Bruce Eckel’s Thinking in Java Contents | Prev | Next In Java 1.1 it’s possible to place a class definition within another class definition. This is called an inner class . The inner class is a useful feature because it allows you to group classes that logically belong together and to control the visibility of […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
19 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

In


Java 1.1


it’s possible to place a class definition within another class
definition. This is called an
inner
class
.
The
inner
class is a useful feature because it allows you to group classes that logically
belong together and to control the visibility of one within the other. However,
it’s important to understand that inner classes are distinctly different
from composition.

Often,


while you

re learning about them, the need for inner classes isn’t


immediately obvious. At the end of this section, after all of the syntax and


semantics of inner classes have been described, you’ll find an example


that should make clear the benefits of inner classes.

You


create an inner class just as you’d expect: by placing the class


definition inside a surrounding class: (See page


97

if you have trouble executing this program.)

//: Parcel1.java
// Creating inner classes
package c07.parcel1;
 
public class Parcel1 {
  class Contents {
    private int i = 11;
    public int value() { return i; }
  }
  class Destination {
    private String label;
    Destination(String whereTo) {
      label = whereTo;
    }
    String readLabel() { return label; }
  }
  // Using inner classes looks just like
  // using any other class, within Parcel1:
  public void ship(String dest) {
    Contents c = new Contents();
    Destination d = new Destination(dest);
  }
  public static void main(String[] args) {
    Parcel1 p = new Parcel1();
    p.ship("Tanzania");
  }
} ///:~ 

The


inner classes, when used inside


ship( )

,


look just like the use of any other classes. Here, the only practical


difference is that the names are nested within


Parcel1

.


You’ll see in a while that this isn’t the only difference.

More


typically, an outer class will have a method that returns a handle to an inner


class, like this:

//: Parcel2.java
// Returning a handle to an inner class
package c07.parcel2;
 
public class Parcel2 {
  class Contents {
    private int i = 11;
    public int value() { return i; }
  }
  class Destination {
    private String label;
    Destination(String whereTo) {
      label = whereTo;
    }
    String readLabel() { return label; }
  }
  public Destination to(String s) {
    return new Destination(s);
  }
  public Contents cont() {
    return new Contents();
  }
  public void ship(String dest) {
    Contents c = cont();
    Destination d = to(dest);
  }
  public static void main(String[] args) {
    Parcel2 p = new Parcel2();
    p.ship("Tanzania");
    Parcel2 q = new Parcel2();
    // Defining handles to inner classes:
    Parcel2.Contents c = q.cont();
    Parcel2.Destination d = q.to("Borneo");
  }
} ///:~ 

If


you want to make an object of the inner class anywhere except from within a non-


static

method of the outer class, you must specify the type of that object as


OuterClassName.InnerClassName

,


as seen in


main( )

.

Inner
classes and upcasting

So


far, inner classes don’t seem that dramatic. After all, if it’s


hiding you’re after, Java already has a perfectly good hiding mechanism


– just allow the class to be “

friendly”
(visible only within a
package)
rather than creating it as an inner class.
However,
inner classes really come into their own when you start upcasting to a base
class, and in particular to an
interface.
(The effect of producing an interface handle from an object that implements it
is essentially the same as upcasting to a base class.) That’s because the
inner class can then be completely unseen and unavailable to anyone, which is
convenient for hiding the implementation. All you get back is a handle to the
base class or the
interface,
and it’s possible that you can’t even find out the exact type, as
shown here:
//: Parcel3.java
// Returning a handle to an inner class
package c07.parcel3;
 
abstract class Contents {
  abstract public int value();
}
 
interface Destination {
  String readLabel();
}
 
public class Parcel3 {
  private class PContents extends Contents {
    private int i = 11;
    public int value() { return i; }
  }
  protected class PDestination
      implements Destination {
    private String label;
    private PDestination(String whereTo) {
      label = whereTo;
    }
    public String readLabel() { return label; }
  }
  public Destination dest(String s) {
    return new PDestination(s);
  }
  public Contents cont() {
    return new PContents();
  }
}
 
class Test {
  public static void main(String[] args) {
    Parcel3 p = new Parcel3();
    Contents c = p.cont();
    Destination d = p.dest("Tanzania");
    // Illegal -- can't access private class:
    //! Parcel3.PContents c = p.new PContents();
  }
} ///:~ 

Now


Contents

and


Destination

represent interfaces available to the client programmer. (The


interface

,


remember, automatically makes all of its members


public.

)


For convenience, these are placed inside a single file, but ordinarily


Contents

and


Destination

would each be


public

in


their own files.

In


Parcel3

,


something new has been added: the inner class


PContents

is


private

so


no one but


Parcel3

can access it.


PDestination

is


protected

,


so no one but


Parcel3

,


classes in the


Parcel3

package (since


protected

also gives package access; that is,


protected

is also “friendly”), and the inheritors of


Parcel3

can


access


PDestination

.


This means that the client programmer has restricted knowledge and access to


these members. In fact, you can’t even downcast to a


private

inner class (or a


protected

inner class unless you’re an inheritor), because you can’t access


the name, as you can see in


class
Test

.


Thus, the


private

inner class provides a way for the class designer to completely prevent any


type-coding dependencies and to completely hide details about implementation.


In addition, extension of an


interface

is useless from the client programmer’s perspective since the client


programmer cannot access any additional methods that aren’t part of the


public


interface

class. This also provides an opportunity for the Java compiler to generate more


efficient code.

Normal


(non-inner) classes cannot be made


private

or


protected


only


public

or “friendly.”

Note


that


Contents

doesn’t need to be an


abstract

class. You could use an ordinary class here as well, but the most typical


starting point for such a design is an


interface

.

Inner
classes in methods and scopes

What


you’ve seen so far encompasses the typical use for inner classes. In


general, the code that you’ll write and read involving inner classes will


be “plain” inner classes that are simple and easy to understand.


However, the design for inner classes is quite complete and there are a number


of other, more obscure, ways that you can use them if you choose: inner classes


can be created within a method or even an arbitrary scope. There are two


reasons for doing this:

  1. As
    shown previously, you’re implementing an interface of some kind so that
    you can create and return a handle.
  2. You’re
    solving a complicated problem and you want to create a class to aid in your
    solution, but you don’t want it publicly available.

In


the following examples, the previous code will be modified to use:

  1. A
    class defined within a method
  2. A
    class defined within a scope inside a method
  3. An
    anonymous
    class implementing an
    interface
  4. An
    anonymous class extending a class that has a non-default constructor
  5. An
    anonymous class that performs field initialization
  6. An
    anonymous class that performs construction
    using instance initialization (anonymous inner classes cannot have constructors)

This


will all take place within the package


innerscopes

.


First, the common interfaces from the previous code will be defined in their


own files so they can be used in all the examples:

//: Destination.java
package c07.innerscopes;
 
interface Destination {
  String readLabel();
} ///:~ 

The


point has been made that


Contents

could be an


abstract

class, so here it will be in a more natural form, as an


interface

:

//: Contents.java
package c07.innerscopes;
 
interface Contents {
  int value();
} ///:~ 

Although


it’s an ordinary class with an implementation,


Wrapping

is also being used as a common “interface” to its derived classes:

//: Wrapping.java
package c07.innerscopes;
 
public class Wrapping {
  private int i;
  public Wrapping(int x) { i = x; }
  public int value() { return i; }
} ///:~ 

You’ll


notice above that


Wrapping

has a constructor that requires an argument, to make things a bit more


interesting.

The


first example shows the creation of an entire class within the scope of a


method (instead of the scope of another class):

//: Parcel4.java
// Nesting a class within a method
package c07.innerscopes;
 
public class Parcel4 {
  public Destination dest(String s) {
    class PDestination
        implements Destination {
      private String label;
      private PDestination(String whereTo) {
        label = whereTo;
      }
      public String readLabel() { return label; }
    }
    return new PDestination(s);
  }
  public static void main(String[] args) {
    Parcel4 p = new Parcel4();
    Destination d = p.dest("Tanzania");
  }
} ///:~ 

The


class


PDestination

is part of


dest( )

rather than being part of


Parcel4.

(Also notice that you could use the class identifier


PDestination

for


an inner class inside each class in the same subdirectory without a name


clash.) Therefore,


PDestination

cannot


be accessed outside of


dest( )

.


Notice


the upcasting that occurs in the return statement – nothing comes out of


dest( )

except a handle to the base class


Destination

.


Of course, the fact that the name of the class


PDestination

is placed inside


dest( )

doesn’t mean that


PDestination

is not a valid object once


dest( )

returns.

The


next example shows how you can nest an

inner
class within any arbitrary scope:
//: Parcel5.java
// Nesting a class within a scope
package c07.innerscopes;
 
public class Parcel5 {
  private void internalTracking(boolean b) {
    if(b) {
      class TrackingSlip {
        private String id;
        TrackingSlip(String s) {
          id = s;
        }
        String getSlip() { return id; }
      }
      TrackingSlip ts = new TrackingSlip("slip");
      String s = ts.getSlip();
    }
    // Can't use it here! Out of scope:
    //! TrackingSlip ts = new TrackingSlip("x");
  }
  public void track() { internalTracking(true); }
  public static void main(String[] args) {
    Parcel5 p = new Parcel5();
    p.track();
  }
} ///:~ 

The


class


TrackingSlip

is nested inside the scope of an


if

statement. This does not mean that the class is conditionally created –


it gets compiled along with everything else. However, it’s not available


outside the scope in which it is defined.



Other


than that, it looks just like an ordinary class.

The


next example looks a little strange:

//: Parcel6.java
// A method that returns an anonymous inner class
package c07.innerscopes;
 
public class Parcel6 {
  public Contents cont() {
    return new Contents() {
      private int i = 11;
      public int value() { return i; }
    }; // Semicolon required in this case
  }
  public static void main(String[] args) {
    Parcel6 p = new Parcel6();
    Contents c = p.cont();
  }
} ///:~ 

The


cont( )

method combines the creation of the return value with the definition of the


class that represents that return value! In addition, the class is anonymous


– it has no name. To make matters a bit worse, it looks like you’re


starting out to create a


Contents

object:

return
new Contents()

but


then, before you get to the semicolon, you say, “But wait, I think


I’ll slip in a class definition”:

return new Contents() {
  private int i = 11;
  public int value() { return i; }
};

What


this strange syntax means is “create an object of an anonymous class


that’s inherited from


Contents

.”


The handle returned by the


new

expression is automatically upcast to a


Contents

handle. The anonymous inner class syntax is a shorthand for:

class MyContents extends Contents {
  private int i = 11;
  public int value() { return i; }
}
return new MyContents();

In


the anonymous inner class,


Contents

is created using a default constructor. The following code shows what to do if


your base class needs a constructor with an argument:

//: Parcel7.java
// An anonymous inner class that calls the 
// base-class constructor
package c07.innerscopes;
 
public class Parcel7 {
  public Wrapping wrap(int x) {
    // Base constructor call:
    return new Wrapping(x) {
      public int value() {
        return super.value() * 47;
      }
    }; // Semicolon required
  }
  public static void main(String[] args) {
    Parcel7 p = new Parcel7();
    Wrapping w = p.wrap(10);
  }
} ///:~ 

That


is, you simply pass the appropriate argument to the base-class constructor,


seen here as the


x

passed


in


new
Wrapping(x)

.


An anonymous class cannot have a constructor where you would normally call


super( )

.

In


both of the previous examples, the semicolon doesn’t mark the end of the


class body (as it does in C++). Instead, it marks the end of the expression


that happens to contain the anonymous class. Thus, it’s identical to the


use of the semicolon everywhere else.

What


happens if you need to perform some kind of initialization for an object of an

anonymous
inner class? Since it’s anonymous, there’s no name to give the
constructor so you can’t have a constructor. You can, however, perform
initialization at the point of definition of your fields:
//: Parcel8.java
// An anonymous inner class that performs 
// initialization. A briefer version
// of Parcel5.java.
package c07.innerscopes;
 
public class Parcel8 {
  // Argument must be final to use inside 
  // anonymous inner class:
  public Destination dest(final String dest) {
    return new Destination() {
      private String label = dest;
      public String readLabel() { return label; }
    };
  }
  public static void main(String[] args) {
    Parcel8 p = new Parcel8();
    Destination d = p.dest("Tanzania");
  }
} ///:~ 

If


you’re defining an anonymous inner class and want to use an object


that’s defined outside the anonymous inner class, the compiler requires


that the outside object be


final

.


This is why the argument to


dest( )

is


final

.


If


you forget, you’ll get a compile-time error message.

As


long as you’re simply assigning a field, the above approach is fine. But


what if you need to perform some constructor-like activity? With Java 1.1


instance
initialization
,
you can, in effect, create a constructor for an anonymous inner class:
//: Parcel9.java
// Using "instance initialization" to perform 
// construction on an anonymous inner class
package c07.innerscopes;
 
public class Parcel9 {
  public Destination
  dest(final String dest, final float price) {
    return new Destination() {
      private int cost;
      // Instance initialization for each object:
      {
        cost = Math.round(price);
        if(cost > 100)
          System.out.println("Over budget!");
      }
      private String label = dest;
      public String readLabel() { return label; }
    };
  }
  public static void main(String[] args) {
    Parcel9 p = new Parcel9();
    Destination d = p.dest("Tanzania", 101.395F);
  }
} ///:~ 

Inside


the instance initializer you can see code that couldn’t be executed as


part of a field initializer (that is, the


if

statement). So in effect, an instance initializer is the constructor for an


anonymous inner class. Of course, it’s limited; you can’t overload


instance initializers so you can have only one of these constructors.


Advertisement

So


far, it appears that inner classes are just a name-hiding and code-organization


scheme, which is helpful but not totally compelling. However, there’s


another twist. When you create an inner class, objects of that inner class have


a link to the enclosing object that made them, and so they can access the


members of that enclosing object –


without

any


special qualifications. In addition,

inner
classes have access rights to all the elements in the enclosing class.
[29]
The following example demonstrates this:
//: Sequence.java
// Holds a sequence of Objects
 
interface Selector {
  boolean end();
  Object current();
  void next();
}
 
public class Sequence {
  private Object[] o;
  private int next = 0;
  public Sequence(int size) {
    o = new Object[size];
  }
  public void add(Object x) {
    if(next < o.length) {
      o[next] = x;
      next++;
    }
  }
  private class SSelector implements Selector {
    int i = 0;
    public boolean end() {
      return i == o.length;
    }
    public Object current() {
      return o[i];
    }
    public void next() {
      if(i < o.length) i++;
    }
  }
  public Selector getSelector() {
    return new SSelector();
  }
  public static void main(String[] args) {
    Sequence s = new Sequence(10);
    for(int i = 0; i < 10; i++)
      s.add(Integer.toString(i));
    Selector sl = s.getSelector();
    while(!sl.end()) {
      System.out.println((String)sl.current());
      sl.next();
    }
  }
} ///:~ 

The


Sequence

is simply a fixed-sized array of


Object

with a class wrapped around it. You call


add( )

to add a new


Object

to the end of the sequence (if there’s room left). To fetch each of the


objects in a


Sequence

,


there’s an interface called


Selector

,


which allows you to see if you’re at the


end( )

,


to look at the


current( )
Object

,


and to move to the


next( )
Object

in the


Sequence

.


Because


Selector

is an


interface

,


many other classes can implement the


interface

in their own ways, and many methods can take the


interface

as an argument, in order to create generic code.

Here,


the


SSelector

is a private class that provides


Selector

functionality. In


main( )

,


you can see the creation of a


Sequence

,


followed by the addition of a number of


String

objects. Then, a


Selector

is produced with a call to


getSelector( )

and this is used to move through the


Sequence

and select each item.

At


first, the creation of


SSelector

looks like just another inner class. But examine it closely. Note that each of


the methods


end( )

,


current( ),

and


next( )

refer to


o

,


which is a handle that isn’t part of


SSelector

,


but is instead a


private

field


in the enclosing class. However, the inner class can access methods and fields


from the enclosing class as if they owned them. This turns out to be very


convenient, as you can see in the above example.

So


an inner class has access to the members of the enclosing class. How can this


happen? The

inner
class must keep a reference to the particular object of the enclosing class
that was responsible for creating it. Then when you refer to a member of the
enclosing class, that (hidden) reference is used to select that member.
Fortunately, the compiler takes care of all these details for you, but you can
also understand now that an object of an inner class can be created only in
association with an object of the enclosing class. The process of construction
requires the initialization of the handle to the object of the enclosing class,
and the compiler will complain if it cannot access the handle. Most of the time
this occurs without any intervention on the part of the programmer.

static
inner classes

To


understand the meaning of

static
when applied to inner classes, you must remember that the object of the inner
class implicitly keeps a handle to the object of the enclosing class that
created it. This is not true, however, when you say an inner class is
static.
A
static
inner
class means:
  1. You
    don’t need an outer-class object in order to create an object of a
    static
    inner class.
  2. You
    can’t access an outer-class object from an object of a
    static
    inner class.

There


are some restrictions:


static

members can be at only the outer level of a class, so inner classes cannot have


static

data or


static

inner classes.

If
you don’t need to create an object of the outer class in order to create
an object of the inner class, you can make everything
static.
For this to work, you must also make the inner classes
static:
//: Parcel10.java
// Static inner classes
package c07.parcel10;
 
abstract class Contents {
  abstract public int value();
}
 
interface Destination {
  String readLabel();
}
 
public class Parcel10 {
  private static class PContents
  extends Contents {
    private int i = 11;
    public int value() { return i; }
  }
  protected static class PDestination
      implements Destination {
    private String label;
    private PDestination(String whereTo) {
      label = whereTo;
    }
    public String readLabel() { return label; }
  }
  public static Destination dest(String s) {
    return new PDestination(s);
  }
  public static Contents cont() {
    return new PContents();
  }
  public static void main(String[] args) {
    Contents c = cont();
    Destination d = dest("Tanzania");
  }
} ///:~ 

In


main( )

,


no object of


Parcel10

is necessary; instead you use the normal syntax for selecting a


static

member to call the methods that return handles to


Contents

and


Destination

.

Normally


you can

t put any code inside an


interface

,


but a


static

inner class can be part of an


interface

.


Since the class is


static

it


doesn

t violate the rules for interfaces – the


static

inner


class is only placed inside the namespace of the interface:

//: IInterface.java
// Static inner classes inside interfaces
 
class IInterface {
  static class Inner {
    int i, j, k;
    public Inner() {}
    void f() {}
  }
} ///:~ 

Earlier


in the book I suggested putting a


main( )

in


every class to act as a test


bed for that class. One drawback to this is the amount of extra code you must
carry around. If this is a problem, you can use a
static
inner class to hold your test code:
//: TestBed.java
// Putting test code in a static inner class
 
class TestBed {
  TestBed() {}
  void f() { System.out.println("f()"); }
  public static class Tester {
    public static void main(String[] args) {
      TestBed t = new TestBed();
      t.f();
    }
  }
} ///:~ 

This


generates a separate class called


TestBed$Tester

(to run the program you say


java
TestBed$Tester

).


You can use this class for testing, but you don

t need to include it in your


shipping product.


Advertisement

Referring
to the outer class object

If


you need to produce the handle to the outer class object, you name the outer


class followed by a dot and


this

.


For example, in the class


Sequence.SSelector

,


any of its methods can produce the stored handle to the outer class


Sequence

by saying


Sequence.this

.


The resulting handle is automatically the correct type. (This is known and


checked at compile time, so there is no run-time overhead.)

Sometimes


you want to tell some other object to create an object of one of its inner


classes. To do this you must provide a handle to the other outer class object


in the


new

expression, like this:

//: Parcel11.java
// Creating inner classes
package c07.parcel11;
 
public class Parcel11 {
  class Contents {
    private int i = 11;
    public int value() { return i; }
  }
  class Destination {
    private String label;
    Destination(String whereTo) {
      label = whereTo;
    }
    String readLabel() { return label; }
  }
  public static void main(String[] args) {
    Parcel11 p = new Parcel11();
    // Must use instance of outer class
    // to create an instances of the inner class:
    Parcel11.Contents c = p.new Contents();
    Parcel11.Destination d =
      p.new Destination("Tanzania");
  }
} ///:~ 

To


create an object of the inner class directly, you don’t follow the same


form and refer to the outer class name


Parcel11

as you might expect, but instead you must use an


object

of the outer class to make an object of the inner class:

Parcel11.Contents
c = p.new Contents();

Thus,


it’s not possible to create an object of the inner class unless you


already have an object of the outer class. This is because the object of the


inner class is quietly connected to the object of the outer class that it was


made from. However, if you make a


static

inner class, then it doesn’t need a handle to the outer class object.


Inheriting
from inner classes

Because


the inner class constructor must attach to a handle of the enclosing class


object, things are slightly complicated when you inherit from an inner class.


The problem is that the “secret” handle to the enclosing class


object


must

be initialized, and yet in the derived class there’s no longer a default


object to attach to. The answer is to use a syntax provided to make the


association explicit:

//: InheritInner.java
// Inheriting an inner class
 
class WithInner {
  class Inner {}
}
 
public class InheritInner
    extends WithInner.Inner {
  //! InheritInner() {} // Won't compile
  InheritInner(WithInner wi) {
    wi.super();
  }
  public static void main(String[] args) {
    WithInner wi = new WithInner();
    InheritInner ii = new InheritInner(wi);
  }
} ///:~ 

You


can see that


InheritInner

is extending only the inner class, not the outer one. But when it comes time to


create a constructor, the default one is no good and you can’t just pass


a handle to an enclosing object. In addition, you must use the syntax

enclosingClassHandle.super(); inside
the constructor. This provides the necessary handle and the program will then
compile.

Advertisement

Can
inner classes be overridden?

What


happens when you create an inner class, then inherit from the enclosing class


and redefine the inner class? That is, is it possible to override an inner


class? This seems like it would be a powerful concept, but

“overriding”
an inner class as if it were another method of the outer class doesn’t
really do anything:
//: BigEgg.java
// An inner class cannot be overriden 
// like a method
 
class Egg {
  protected class Yolk {
    public Yolk() {
      System.out.println("Egg.Yolk()");
    }
  }
  private Yolk y;
  public Egg() {
    System.out.println("New Egg()");
    y = new Yolk();
  }
}
 
public class BigEgg extends Egg {
  public class Yolk {
    public Yolk() {
      System.out.println("BigEgg.Yolk()");
    }
  }
  public static void main(String[] args) {
    new BigEgg();
  }
} ///:~ 

The


default constructor is synthesized automatically by the compiler, and this


calls the base-class default constructor. You might think that since a


BigEgg

is being created, the “overridden” version of


Yolk

would be used, but this is not the case. The output is:

New Egg()
Egg.Yolk()

This


example simply shows that there isn’t any extra inner class magic going


on when you inherit from the outer class. However, it’s still possible to


explicitly inherit from the inner class:

//: BigEgg2.java
// Proper inheritance of an inner class
 
class Egg2 {
  protected class Yolk {
    public Yolk() {
      System.out.println("Egg2.Yolk()");
    }
    public void f() {
      System.out.println("Egg2.Yolk.f()");
    }
  }
  private Yolk y = new Yolk();
  public Egg2() {
    System.out.println("New Egg2()");
  }
  public void insertYolk(Yolk yy) { y = yy; }
  public void g() { y.f(); }
}
 
public class BigEgg2 extends Egg2 {
  public class Yolk extends Egg2.Yolk {
    public Yolk() {
      System.out.println("BigEgg2.Yolk()");
    }
    public void f() {
      System.out.println("BigEgg2.Yolk.f()");
    }
  }
  public BigEgg2() { insertYolk(new Yolk()); }
  public static void main(String[] args) {
    Egg2 e2 = new BigEgg2();
    e2.g();
  }
} ///:~ 

Now


BiggEgg2.Yolk

explicitly


extends
Egg2.Yolk

and overrides its methods. The method


insertYolk( )

allows


BigEgg2

to


upcast one of its own


Yolk

objects


into the


y

handle in


Egg2

,


so when


g( )

calls


y.f( )

the overridden version of


f( )

is used. The output is:

Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()

The


second call to


Egg2.Yolk( )

is the base-class constructor call of the


BigEgg2.Yolk

constructor. You can see that the overridden version of


f( )

is used when


g( )

is called.


Inner
class identifiers

Since


every class produces a


.class

file


that holds all the information about how to create objects of this type (this


information produces a meta-class called the


Class

object),


you might guess that

inner
classes must also produce
.class
files to contain the information for
their
Class
objects. The names of these files/classes have a strict formula: the name of
the enclosing class, followed by a ‘
$’,
followed by the name of the inner class. For example, the
.class
files created by
InheritInner.java
include:
InheritInner.class
WithInner$Inner.class
WithInner.class

If


inner classes are anonymous, the compiler simply starts generating numbers as


inner class identifiers. If inner classes are nested within inner classes,


their names are simply appended after a ‘


$


and the outer class identifier(s).

Although


this scheme of generating internal names is simple and straightforward,


it’s also robust and handles most situations.


[30]

Since it is the standard naming scheme for Java, the generated files are


automatically platform-independent. (Note that the Java compiler is changing


your inner classes in all sorts of other ways in order to make them work.)


Advertisement

Why
inner classes: control frameworks

At


this point you’ve seen a lot of syntax and semantics describing the way


inner classes work, but this doesn’t answer the question of why they


exist. Why did Sun go to so much trouble to add such a fundamental language


feature in Java 1.1

?
The answer is something that I will refer to here as a
control
framework
.

An


application
framework

is a class or a set of classes that’s designed to solve a particular type
of problem. To apply an application framework, you inherit from one or more
classes and override some of the methods. The code you write in the overridden
methods customizes the general solution provided by that application framework
to solve your specific problem. The control framework is a particular type of
application

framework
dominated by the need to respond to events; a system that primarily responds to
events is called an
event-driven
system.
One of the most important problems in application programming is the
graphical
user interface (GUI), which is almost entirely event-driven. As you will see in
Chapter 13, the Java 1.1 AWT is a control framework that elegantly solves the
GUI problem using inner classes.

To


see how inner classes allow the simple creation and use of control frameworks,


consider a control framework whose job is to execute events whenever those


events are “ready.” Although “ready” could mean


anything, in this case the default will be based on clock time. What follows is


a control framework that contains no specific information about what it’s


controlling. First, here is the interface that describes any control event.


It’s an


abstract

class instead of an actual


interface

because the default behavior is control based on time, so some of the


implementation can be included here:

//: Event.java
// The common methods for any control event
package c07.controller;
 
abstract public class Event {
  private long evtTime;
  public Event(long eventTime) {
    evtTime = eventTime;
  }
  public boolean ready() {
    return System.currentTimeMillis() >= evtTime;
  }
  abstract public void action();
  abstract public String description();
} ///:~ 

The


constructor simply captures the time when you want the


Event

to run, while


ready( )

tells you when it’s time to run it. Of course,


ready( )

could be overridden in a derived class to base the


Event

on something other than time.

action( )

is the method that’s called when the


Event

is


ready( )

,


and


description( )

gives textual information about the


Event

.

The


next file contains the actual control framework that manages and fires events.


The first class is really just a “helper” class whose job is to hold


Event

objects. You could replace it with any appropriate collection, and in Chapter 8


you’ll discover other collections that will do the trick without


requiring you to write this extra code:

//: Controller.java
// Along with Event, the generic
// framework for all control systems:
package c07.controller;
 
// This is just a way to hold Event objects.
class EventSet {
  private Event[] events = new Event[100];
  private int index = 0;
  private int next = 0;
  public void add(Event e) {
    if(index >= events.length)
      return; // (In real life, throw exception)
    events[index++] = e;
  }
  public Event getNext() {
    boolean looped = false;
    int start = next;
    do {
      next = (next + 1) % events.length;
      // See if it has looped to the beginning:
      if(start == next) looped = true;
      // If it loops past start, the list 
      // is empty:
      if((next == (start + 1) % events.length)
         && looped)
        return null;
    } while(events[next] == null);
    return events[next];
  }
  public void removeCurrent() {
    events[next] = null;
  }
}
 
public class Controller {
  private EventSet es = new EventSet();
  public void addEvent(Event c) { es.add(c); }
  public void run() {
    Event e;
    while((e = es.getNext()) != null) {
      if(e.ready()) {
        e.action();
        System.out.println(e.description());
        es.removeCurrent();
      }
    }
  }
} ///:~ 
EventSet

arbitrarily holds 100


Event

s.


(If a “real” collection from Chapter 8 is used here you don’t


need to worry about its maximum size, since it will resize itself). The


index

is used to keep track of the next available space, and


next

is used when you’re looking for the next


Event

in the list, to see whether you’ve looped around. This is important


during a call to


getNext( )

,


because


Event

objects are removed from the list (using


removeCurrent( )

)


once


they’re run, so


getNext( )

will encounter holes in the list as it moves through it.

Note


that


removeCurrent( )

doesn’t just set some flag indicating that the object is no longer in


use. Instead, it sets the handle to


null

.


This is important because if the

garbage
collector sees a handle that’s still in use then it can’t clean up
the object. If you think your handles might hang around (as they would here),
then it’s a good idea to set them to
null
to give the garbage collector permission to clean them up.
Controller

is where the actual work goes on. It uses an


EventSet

to hold its


Event

objects, and


addEvent( )

allows you to add new events to this list. But the important method is


run( )

.


This method loops through the


EventSet

,


hunting for an


Event

object that’s


ready( )

to run. For each one it finds


ready( )

,


it


calls the


action( )

method, prints out the


description( ),

and then removes the


Event

from the list.

Note


that so far in this design you know nothing about exactly


what

an


Event

does. And this is the crux of the design; how it “separates the things


that change from the things that stay the same.” Or, to use my term, the


vector
of change” is the different actions of the various kinds of
Event
objects, and you express different actions by creating different
Event
subclasses.

This


is where inner classes come into play. They allow two things:

  1. To
    express the entire implementation of a control-framework application in a
    single class, thereby encapsulating everything that’s unique about that
    implementation. Inner classes are used to express the many different kinds of
    action( )
    necessary to solve the problem. In addition, the following example uses private
    inner classes so the implementation is completely hidden and can be changed
    with impunity.
  2. Inner
    classes keep this implementation from becoming awkward, since you’re able
    to easily access any of the members in the outer class. Without this ability
    the code might become unpleasant enough that you’d end up seeking an
    alternative.

Consider


a particular implementation of the control framework designed to control


greenhouse functions.


[31]

Each action is entirely different: turning lights, water, and thermostats on


and off, ringing bells, and restarting the system. But the control framework is


designed to easily isolate this different code. For each type of action you


inherit a new


Event

inner class, and write the control code inside of


action( )

.

As


is typical with an application framework, the class


GreenhouseControls

is inherited from


Controller

:

//: GreenhouseControls.java
// This produces a specific application of the
// control system, all in a single class. Inner
// classes allow you to encapsulate different
// functionality for each type of event.
package c07.controller;
 
public class GreenhouseControls
    extends Controller {
  private boolean light = false;
  private boolean water = false;
  private String thermostat = "Day";
  private class LightOn extends Event {
    public LightOn(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here to 
      // physically turn on the light.
      light = true;
    }
    public String description() {
      return "Light is on";
    }
  }
  private class LightOff extends Event {
    public LightOff(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here to 
      // physically turn off the light.
      light = false;
    }
    public String description() {
      return "Light is off";
    }
  }
  private class WaterOn extends Event {
    public WaterOn(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here
      water = true;
    }
    public String description() {
      return "Greenhouse water is on";
    }
  }
  private class WaterOff extends Event {
    public WaterOff(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here
      water = false;
    }
    public String description() {
      return "Greenhouse water is off";
    }
  }
  private class ThermostatNight extends Event {
    public ThermostatNight(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here
      thermostat = "Night";
    }
    public String description() {
      return "Thermostat on night setting";
    }
  }
  private class ThermostatDay extends Event {
    public ThermostatDay(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Put hardware control code here
      thermostat = "Day";
    }
    public String description() {
      return "Thermostat on day setting";
    }
  }
  // An example of an action() that inserts a 
  // new one of itself into the event list:
  private int rings;
  private class Bell extends Event {
    public Bell(long eventTime) {
      super(eventTime);
    }
    public void action() {
      // Ring bell every 2 seconds, rings times:
      System.out.println("Bing!");
      if(--rings > 0)
        addEvent(new Bell(
          System.currentTimeMillis() + 2000));
    }
    public String description() {
      return "Ring bell";
    }
  }
  private class Restart extends Event {
    public Restart(long eventTime) {
      super(eventTime);
    }
    public void action() {
      long tm = System.currentTimeMillis();
      // Instead of hard-wiring, you could parse
      // configuration information from a text
      // file here:
      rings = 5;
      addEvent(new ThermostatNight(tm));
      addEvent(new LightOn(tm + 1000));
      addEvent(new LightOff(tm + 2000));
      addEvent(new WaterOn(tm + 3000));
      addEvent(new WaterOff(tm + 8000));
      addEvent(new Bell(tm + 9000));
      addEvent(new ThermostatDay(tm + 10000));
      // Can even add a Restart object!
      addEvent(new Restart(tm + 20000));
    }
    public String description() {
      return "Restarting system";
    }
  }
  public static void main(String[] args) {
    GreenhouseControls gc =
      new GreenhouseControls();
    long tm = System.currentTimeMillis();
    gc.addEvent(gc.new Restart(tm));
    gc.run();
  }
} ///:~ 

Note


that


light

,


water

,


thermostat,

and


rings

all belong to the outer class


GreenhouseControls

,


and yet the inner classes have no problem accessing those fields. Also, most of


the


action( )

methods also involve some sort of hardware control, which would most likely


involve calls to non-Java code.

Most


of the


Event

classes look similar, but


Bell

and


Restart

are special.


Bell

rings, and if it hasn’t yet rung enough times it adds a new


Bell

object to the event list, so it will ring again later. Notice how inner classes


almost

look like multiple inheritance:


Bell

has all the methods of


Event

and it also appears to have all the methods of the outer class


GreenhouseControls

.

Restart

is responsible for initializing the system, so it adds all the appropriate


events. Of course, a more flexible way to accomplish this is to avoid


hard-coding the events and instead read them from a file. (An exercise in


Chapter 10 asks you to modify this example to do just that.) Since


Restart( )

is just another


Event

object, you can also add a


Restart

object within


Restart.action( )

so that the system regularly restarts itself. And all you need to do in


main( )

is create a


GreenhouseControls

object and add a


Restart

object to get it going.

This


example should move you a long way toward appreciating the value of inner


classes, especially when used within a control framework. However, in the


latter half of Chapter 13 you’ll see how elegantly inner classes are used


to describe the actions of a graphical user interface. By the time you finish


that section you should be fully convinced.



[29]

This is very different from the design of


nested
classes

in C++, which is simply a name-hiding mechanism. There is no link to an


enclosing object and no implied permissions in C++.

[30]

On the other hand, ‘$’ is a meta-character to the Unix shell and so


you’ll sometimes have trouble when listing the


.class

files. This is a bit strange coming from Sun, a Unix-based company. My guess is


that they weren’t considering this issue, but instead thought you’d


naturally focus on the source-code files.

[31]

For some reason this has always been a pleasing problem for me to solve; it


came from


C++
Inside & Out

,


but Java allows a much more elegant solution.

Contents

|

Prev

|

Next
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.