Mike Slinn

Instantiating Java Inner Classes

Published 2005-12-30.
Time to read: 1 minutes.

This page is part of the posts collection, categorized under Java.

I've been writing Java code for years. Today I learned something new. I have been adding a new feature to Zamples that was best expressed as a doubly nested inner class. The hierarchy looks like this:

public class CodeRange {
   public CodeRange(String str) { /* ... */ }
public class RangeSpec { public RangeSpec(int i, int j) { /* ... */ } public RangeSpec(RangeItem start, RangeItem end) { /* ... */ }
public class RangeItem { public RangeItem(String str, int i) { /* ... */ } } } }

When it came time to write JUnit tests, I needed to instantiate the hierarchy. The syntax surprised me:

CodeRange.RangeSpec.RangeItem range =
   new CodeRange("test").new RangeSpec(1, 1).new  RangeItem("middle", 3);

Not exactly intuitive, eh? It gets even more interesting when trying to write unit tests for the second RangeSpec constructor, the one that accepts two RangeItems. I found I had to create a protected no-args constructor for RangeSpec with an empty body, plus a method within RangeSpec to create RangeItems on demand:

/** For JUnit only */
   protected RangeSpec() {}
/** For JUnit only */ protected RangeItem newRangeItem(String searchString, int offset) { return new RangeItem(searchString, offset); }

Now I could write my test case setup code:

codeRange = new CodeRange(code, "");
   CodeRange.RangeSpec.RangeItem rangeItemStart =
      codeRange.new RangeSpec().newRangeItem("middle", 3);
   CodeRange.RangeSpec.RangeItem rangeItemEnd =
      codeRange.new RangeSpec().newRangeItem("back", 0);
CodeRange.RangeSpec rangeSpec = codeRange.new RangeSpec(rangeItemStart, rangeItemEnd); /* ... */

Everything I read about doubly nested classes amounted to a warning to the effect that they should be avoided. I never had occasion to need this type of solution before, however the particular problem I am solving yields very nicely to this approach. It is simple, elegant and efficient. Don't believe everything you read (except this blog!) 😉.

* indicates a required field.

Please select the following to receive Mike Slinn’s newsletter:

You can unsubscribe at any time by clicking the link in the footer of emails.

Mike Slinn uses Mailchimp as his marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp’s privacy practices.