It often happens that your class needs to organize groups of field values and/or operations in a single unit in a way that no other class uses. For this, there are nested classes.

Nested classes come in two flavors: static (called–would you believe?–static nested classes; and non-static (called internal classes).

Because nested classes aren’t known to the outside world, they are encapsulated within their enclosing classes (which is a good thing) and make code easier to maintain.

Nested class instances are tied to a particular instance of their outer class, and have a built-in reference back to it which can come in handy. Static internal classes are not bound to an instance of their containing class.

Consider the following code:

package org.practicaljava.sandbox;

public class Sandbox {
    private String sandboxId;
    private NestedGrainOfSand nestedGrain;
    private StaticGrainOfSand staticGrain;

    public Sandbox(String sandboxId) {
		this.sandboxId = sandboxId;
    }

    public void print() {
	System.out.println("sandbox=" + sandboxId);
	System.out.println();
	nestedGrain.print();
	System.out.println();
	staticGrain.print();
    }

    private class NestedGrainOfSand {
	private String grainId;
	public NestedGrainOfSand(String grainId) {
	    this.grainId = grainId;
	}

	public void print() {
	    System.out.println("nestedGrainOfSand=" + grainId);
	    System.out.println("parent sandbox=" + Sandbox.this.sandboxId);
	}
    }

    private static class StaticGrainOfSand {
	private String grainId;

	public StaticGrainOfSand(String grainId) {
	    this.grainId = grainId;
	}

	public void print() {
	    System.out.println("staticGrainOfSand=" + grainId);
	}
    }

    public static void main(String[] args) {
	Sandbox sandbox1 = new Sandbox("sandbox1");
	sandbox1.nestedGrain = sandbox1.new NestedGrainOfSand("nestedGrain1");
	sandbox1.staticGrain = new StaticGrainOfSand("staticGrain1");
	sandbox1.print();
    }
}

NestedGrainOfSand is a nested class; it doesn’t have the static modifier. Notice how in its print() method, it can refer to the instance of Sandbox within which it resides: Sandbox.this.

StaticGrainOfSand is a static nested class, and doesn’t belong to any containing instance.

Note also the differences in how the two types of nested classes are instantiated. StaticGrainOfSand is created the same as any non-nested class. But NestedGrainOfSand is instantiated thus:

sandbox1.new NestedGrainOfSand("nestedGrain1")

Qualifying “new” with “sandbox1” indicates who the parent of the new NestedGrainOfSand is.

A nested class is typically a POJO (Plain Old Java Object): a class that contains only data fields plus getters and setters for them, and does not extend other classes or implement any interfaces. For example, a POJO to contain a phone number might look like this:

private class PhoneNumber {
   private String areaCode;
   private String exchange;
   private String phone;

   public getAreaCode() {
       return areaCode;
   }

   public setAreaCode(String areaCode) {
       this.areaCode = areaCode;
   }

   public getExchange() {
       return exchange;
   }
    ...
}

In personal experience, nested classes tend to have other fields that may require manipulation, and I like to pass initialization values to a constructor. Whatever it takes.

What You Need to Know

  • Nested classes are classes defined within containing classes, and not visible to other classes.
  • Static nested class instances are independent of instances of their containing class.
  • Instances of internal classes–nested classes that are not static–belong to an instance of the containing class, and contain a pointer back to the containing-class instance to which they belong.

Next: Interfaces