Class Classes

Goals

Concepts

Language

Library

Lesson

Inner Classes

You've been taught that every new class you write should go in a separate .java file named after the class, and generally that is true. But you can also define a class inside another class; this is called an inner class. Why would you want to do this? It has mostly to do with program organization. Perhaps the class relates only to the outer class (the class in which it is defined) and not appropriate for use by other classes.

Static Inner Classes

We could create a Tank class for storing fuel for a MotorVehicle, and because this would be different than other tanks (an oil tank or an army tank), we could define it inside the MotorVehicle class itself, creating a static inner class.

MotorVehicle class with a Tank static inner class.
public class MotorVehicle extends Vehicle {

  private final Tank tank;

  public Tank getTank() {
    return tank;
  }

  public MotorVehicle() {
    tank = new Tank(60);
  }

  …

  public static class Tank {  //static inner class

    private final long capacity;

    public long getCapacity() {
      return capacity;
    }

    private long amount = 0;

    public long getAmount() {
      return amount;
    }

    public void add(final long amount) {
      checkArgument(this.amount + amount <= getCapacity());
      this.amount += amount;
    }

    public void drain(final long amount) {
      checkArgument(this.amount - amount >= 0);
      this.amount -= amount;
    }

    /** @param capacity The tank capacity, in liters. */
    private Tank(final long capacity) {
      this.capacity = capacity;
    }
  }

}
final MotorVehicle motorVehicle = new MotorVehicle();
final MotorVehicle.Tank tank = motorVehicle.getTank();
tank.add(20);  //add fuel to the tank

Non-Static Inner Classes

We can also create inner classes that are not static. These classes can only be instantiated in the context of an instance of the outer class. In other words, you cannot create one by itself; its outer class must be instantiated. An instance of a non-static inner class has access to all the instance variables and methods of the outer class. This is one way to create “helper functionality”.

MotorVehicle class with a Tank static inner class.
public class MotorVehicle extends Vehicle {

  private boolean on = false;

  public boolean isOn() {
    return on;
  }

  private final Tank tank;

  public Tank getTank() {
    return tank;
  }

  private final Engine engine;

  public MotorVehicle() {
    tank = new Tank(60);
    engine = new Engine();
  }

  /** Starts the vehicle. */
  public void go() {
    on = true;
    try {
      engine.run();
    } finally {
      on = false;
    }
  }

  …

  private class Engine {  //non-static inner class

    private boolean on = false;

    public boolean isOn() {
      return on;
    }

    /** Runs the engine as long as there is fuel.
     * The vehicle must be running.
     * @throws IllegalStateException if the vehicle is not running.
     */
    public void run() {
      checkState(MotorVehicle.this.isOn(), "Vehicle must be on for engine to run.");
      on = true;
      try {
        while(getTank().getAmount() > 0) {
          getTank().drain(1);  //use some fuel
          //TODO move wheels
        }
      } finally {
        on = false;
      }
    }
  }
}
final MotorVehicle motorVehicle = new MotorVehicle();
motorVehicle.getTank().add(20);  //add fuel to the tank
motorVehicle.go();

Anonymous Classes

Java allows you to extend a class (or implement an interface) on the fly without creating a separate format class definition. The class is anonymous because it has no name, which implies that no one can make another instance of that class. Essentially you define the class and instantiate it in one fell swoop. Normally this is done to implement an abstract method on the fly for a utility class.

Consider an AbstractEngine that is defined in a separate class, requiring the implementation of a showWarning(…) method for indicating that the engine is overheating, for example. A MotorVehicle class could create an anonymous subclass of AbstractEngine, implementing the showWarning(…) method on the fly.

MotorVehicle class implementing AbstractEngine as an anonymous class.
public abstract class AbstractEngine {

  …

  public abstract void showWarning(@Nonnull String message);

}
public class MotorVehicle extends Vehicle {

  private final AbstractEngine engine;

  public MotorVehicle() {
    engine = new AbstractEngine() {  //anonymous class
      @Override
      public void showWarning(@Nonnull String message) {
        System.out.println(message);
      }
    };  //note the semicolon to end the expression
  }
}

Because the anonymous class is defined in the scope of the MotorVehicle, it has access to all the variables and methods of the MotorVehicle instance, just like an inner class. Things get more interesting then if the MotorVehicle already has a way to display warnings to the user. In this case, the anonymous class can simply delegate to the MotorVehicle's functionality.

Anonymous AbstractEngine instance delegating to enclosing MotorVehicle class instance.
public class MotorVehicle extends Vehicle {

  private final AbstractEngine engine;

  protected void reportProblem(@Nonnull String message) {
    System.out.println(message);
  }

  public MotorVehicle() {
    engine = new AbstractEngine() {  //anonymous class
      @Override
      public void showWarning(@Nonnull String message) {
        reportProblem(message);
      }
    };
  }
}

You can create anonymous implementations of interfaces on the fly as well. When learning about generics you learned how it could be useful to create a read-only, empty list and cast it to some generic type on the fly so that it could be used in various situations. Rather than creating a separate EmptyLinkedList<E> class, you could create an anonymous implementation of LinkedList<E> to use as the shared empty list instance.

Creating an anonymous instance of a LinkedList<E> and using it in a Zoo class.
public class DataStructureUtils {

  //instance of anonymous implementation of LinkedList<E>, stored for future use
  private final static LinkedList<Object> EMPTY_LINKED_LIST = new LinkedList<Object>() {

    @Override public getLength() {
      return 0;
    }

    @Override public add(E element) {
      throw new UnsupportedOperationException("This list is read-only.");
    }

    …
  };

  /** @return A shared instance of a read-only, empty linked list. */
  @SuppressWarnings("unchecked")
  public static <E> LinkedList<E> emptyLinkedList() {
    return (LinkedList<E>)EMPTY_LINKED_LIST;
  }

}
public class Zoo {

  …

  public LinkedList<Animal> getAnimals() {
    if(animalCount == 0) {  //if there are no animals in the zoo
      return DataStructureUtils.emptyLinkedList();
    }
  }

}

A Class is a Class<T>

When you create a new FooBar class, the resulting object is an instance of FooBar, as you would expect.

final FooBar fooBar = new FooBar();
System.out.println(fooBar instanceof FooBar); //prints "true"

You also know that if FooBar has any static variables, they live independent of any instance of FooBar. That's because the FooBar class itself is an object! For every class (and interface) you access, from FooBar to Animal to Vehicle, Java will create an object to represent that class. The object representing the class is accessed via a .class member that is present for every class. For example, FooBar.class provides a reference to the object that represents the FooBar class.

Every object is an instance of some class, and in fact every class is an instance of the Class<T> class. Note that Class<T> uses generics. The generic type <T> refers to the type of the class, and you'll soon see how this can be useful.

final Class<FooBar> fooBarClass = FooBar.class;
System.out.println(fooBarClass instanceof FooBar); //prints "false"
System.out.println(fooBarClass instanceof Class); //prints "true"

The Class<T> class has all sorts of interesting properties, such as java.lang.Class.getName() which returns the full name of the class.

System.out.println(FooBar.class.getName());  //prints "com.example.FooBar"

Checking Class<T> Instances

Another useful method is java.lang.Class.isInstance(Object obj), which checks to see if some object is an instance of the given class. This method functions identically to the instanceof operator, with the added benefit that you can use it for some instance of a Class<> even if you don't know what class it is!

Casting Class<T> Instances

Once you know that an object is the instance of some Class<T>, you can cast the instance to type T using the java.lang.Class.cast(Object obj) method.

Getting a Class<T> from an Instance

There is another way to find a class object. If you only have a reference to an object, you can get a reference to that object's class instance by calling java.lang.Object.getClass(). This is possible because the method getClass() is defined in the java.lang.Object class, and every class extends from Object—even Class<T>!

final Truck truck = new Truck();
final Class<Truck> truckClass1 = Truck.class;
final Class<? extends Truck> truckClass2 = truck.getClass();
System.out.println(truckClass1 == truckClass2);  //prints "true"

Review

In the Real World

Self Evaluation

Task

In your Booker application create a getPublicationsByType(…) method. One of its parameters will be a linked list, using generics to allow a linked list of any publication type. The second parameter will be a Class<>, but it must of a Publication or subclass. Pick out all the publications of the given type and return a new linked list (of the captured type of the class) containing only publications of that type. Here's how it the method might be called:

final LinkedList<Book> books = getPublicationsByType(publicationList, Book.class);

Create appropriate unit tests of getPublicationsByType(…), including the following

  1. Create a list of books, magazines, and journals.
  2. Call getPublicationsByType(publicationList, Periodical.class), storing the result in a LinkedList<Periodical>.
  3. Ensure that the returns list is the expected size, and that it contains only periodicals.

Finally refactor each of your methods that prints a certain type of publication, such as printBooks(). Rather than searching through the list and printing the correct type of publication, delegate to your new getPublicationsByType(…) method to retrieve a list containing only publications of the correct type. Then iterate through the new list and print those publications with no further need to check types or perform any additional casting.

See Also