The Pragmatic Craftsman :: Simplicity from complexity : by Stanley Kubasek ::

Java Inner Classes – Intro

I believe in writing self-documented, easy to read code. I believe in mantra that simple is beautiful Inner classes are not good tools for that task. I think they make the task of writing good code much harder: weird syntax, different rules, etc. Mostly for that reason, I have not really learned inner classes. I rarely use them. But whether you like inner classes or not, they are a fundamental feature of Java. You can find examples of inner classes in the Java collections. Map.Entry is one example.

Where am I going with this? I think inner classes come useful in some circumstances. You can develop some really complex features with them. And as a Java developer, you should know what’s in your toolbox. Sooner or later you will come across them. You might have to read code that uses them. Or you might utilize them to make your task easier.

Either way, it’s time to learn inner classes.

My goal here is to create a series of articles/tutorials on inner classes with a goal of learning them on a more deeper level. I came across some very good references on inner classes in Thinking Java book by Bruce Eckel. I’ll mostly use that book, plus some other references for this series.

Inner Classes

What’s an inner class? It’s a class defined within another class.

public class Outer {
  public class Inner {
    // inner fields, methods, etc
  }
}

Simple, right? That’s basically where it ends. Inner classes have more privileges than regular classes. There are different types of inner classes. Like I said, it’s a beast.

One nice thing about inner classes is that they allow you to group related classes together. Comes in handy at times.

Take a look at the example above one more time. How would you create an instance of Inner?

Inner inner = new Inner(); // not going to work

// how about -- seems like this should work
Inner = new Outer.Inner();

// getting closer, but still not there
// let's try to first create an instance of outer
// and then use that to create an instance of inner
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

Yes! That will work. But look at the syntax! :-( Looks really weird to me. outer.new Inner() — but yes, that’s how you create an instance of inner.

One way to get around this weird syntax that Bruce Eckel uses is to create a method in outer that creates an instance of inner.

public class Outer {
  public class Inner {
    // inner fields, methods, etc
  }

  public Inner innerInstance() {
    return new Inner();
  }
}

// now you can use
Outer outer = new Outer();
Outer.Inner inner = outer.innerInstance();

I like that approach. Makes it much more readable.

Inner Class Features

So far, you’ve only seen how you would create an inner class. But what’s really different about an inner class?

    Inner class…

  • Has access to everything in the enclosing class (can access private variables and functions)
  • Can be private. You can’t do that with a regular class. If it is, only the outer class can instantiate it.

Here’s a good example from Thinking in Java:

// Holds a sequence of Objects.
interface Selector {
  boolean end();
  Object current();
  void next();
}

public class Sequence {
  private Object[] items;
  private int next = 0;

  public Sequence(int size) {
    items = new Object[size];
  }

  public void add(Object x) {
    if (next < items.length) items[next++] = x;
  }

  private class SequenceSelector implements Selector {
    private int i = 0;

    public boolean end() {
      return i == items.length;
    }

    public Object current() {
      return items[i];
    }

    public void next() {
      if (i < items.length)
        i++;
    }
  }

  public Selector selector() {
    return new SequenceSelector();
  }

  public static void main(String[] args) {
    Sequence sequence = new Sequence(10);
    for (int i = 0; i < 10; i++)
      sequence.add(Integer.toString(i));
      Selector selector = sequence.selector();
      while (!selector.end()) {
        System.out.print(selector.current() + " ");
        selector.next();
      }
    }
  }

/** Output: 0 1 2 3 4 5 6 7 8 9*/

Note that SequenceSelector is a private class, and how end(), current(), and next() access fields in the enclosed class. Pretty neat, actually.

Accessing Outer Instance

How would you access the outer object from within the inner? Guess what, another “tricky” syntax: Outer.this

public class SimpleOuter {
  private String name;
  private String getName() {
    return this.name;
  }

  private void setName(String name) {
    this.name = name;
  }

  public class Inner {
    public void accessOuter() {
      // note the SYNTAX
      SimpleOuter.this.setName("Test");
      System.out.println("Outer name: " + SimpleOuter.this.getName());
    }
  }

  public Inner inner() {
    return new Inner();
  }

  public static void main(String[] args) {
    SimpleOuter outer = new SimpleOuter();
    SimpleOuter.Inner inner = outer.inner();
    inner.accessOuter();
  }
}
/* Output:Outer name: Test*/

More…

You can’t create an instance of an inner class without creating an outer instance first and using that instance to create the inner. Well, there is, if the inner is static (called nested class). More to come in Part 2…

Favorite Quote

Topics

Tags

Archive

Currently Reading

Info

© 2001-2024 Stanley Kubasek About me :: Contact me

Me on Twitter

»see more

Recent Entries