facebook google plus twitter
Webucator's Free Java Tutorial

Lesson: Inner Classes

Welcome to our free Java tutorial. This tutorial is based on Webucator's Introduction to Java Training course.

In this lesson, you will learn how inner classes are used in Java.

Lesson Goals

  • Learn about the creation and use of inner classes.
  • Learn how to create and use enum classes.

Inner Classes, aka Nested Classes

Inner classes, also known as nested classes are classes defined within another class.

They may be defined as public, protected, private, or with package access.

They may only be used "in the context" of the containing class (outer class or enclosing class), unless they are marked as static.

  • The outer class can freely instantiate inner-class objects within its code; these objects are automatically associated with the outer class instance that created them.
  • Code in some other class can instantiate an inner class object associated with a specific instance of the outer class if the inner-class definition is public (and its containing class is public as well).
  • If the inner class is static, then it can be instantiated without an outer class instance; otherwise, the inner class object must be attached to an instance of the outer class.

Inner classes are used to do the following (these uses overlap to some extent):

  • Create a type of object that is only needed within one class, usually for some short-term purpose.
  • Create a utility type of object that cannot be used elsewhere (which would allow the programmer to change it without fear of repercussions in other classes).
  • Create one-of-a-kind interface implementations (such as individualized event handlers).
  • Allow a sort of multiple inheritance, since the inner class may extend a different class than the outer class extends, and an inner class instance would have access to its private elements as well as the private elements of the outer class object to which it is attached.
  • Implement one-to-many relationships where the classes are tightly coupled (meaning that code for one or both of the classes needs access to many of the private elements of the other class) - the outer class would be the "one" side of the relationship, with the inner class being the "many" side.
  • Provide a specialized form of callback, with which a class may pass very limited access to some of its internal components. Note that:
    • The collections classes provide an iterator, a class that implements the Iterator interface to loop through the elements in the collection using hasNext and next methods.
    • Given that the internal structure of the collection may be complex, implementing the iterator as an inner class enables it to navigate the structure, while not exposing any other aspects of the collection to the outside world.

Inner class code has free access to all elements of the outer class object that contains it, by name (no matter what the access level of the elements is).

Outer class code has free access to all elements in any of its inner classes, no matter what their access term.

An inner class compiles to its own class file, separate from that of the outer class (the name of the file will be OuterClassName$InnerClassName.class, although within your code the name of the class will be OuterClassName.InnerClassName); you cannot use the dollar sign version of the name in your code.

An inner class occupies its own memory block, separate from the outer-class memory block.

An inner class may extend one class, which might be unrelated to the class the outer class extends.

An inner class can implement one or more interfaces and, if treated as an instance of one of its interfaces, external code may have no knowledge that the object actually comes from an inner class.

Inner Class Syntax

Syntax

[modifiers] class OuterClassName {
code
[modifiers] class InnerClassName
[extends BaseClassToInner]
[implements SomeInterface[, MoreInterfaces, ...]] {
fields and methods
}

The definition of the inner class is always available for the outer class to use. Note that:

  • No inner class objects are automatically instantiated with an outer class object.
  • Outer class code may instantiate any number of inner class objects - none, one, or many.

Code Sample:

Java-InnerClasses/Demos/MyOuter.java
public class MyOuter {
  private int x;
  MyOuter(int x, int y) {
    this.x = x;
    new MyInner(y).privateDisplay();
  }
  public class MyInner {
    private int y;
    MyInner(int y) {
      this.y = y;
    }
    private void privateDisplay() {
      System.out.println("privateDisplay x = " + x + " and y = " + y);
    }
    public void publicDisplay() {
      System.out.println("publicDisplay x =  " + x + " and y = " + y);
    }
  }
}

Code Explanation

This is a simple example of an inner class

  • MyOuter has one property, x; the inner class MyInner has one property, y.
  • The MyOuter constructor accepts two parameters; the first is used to populate x.
  • It creates one MyInner object, whose y property is populated with the second parameter.
  • Note that the inner class has free access to the private outer class x element.
  • The outer class has free access to the private inner class privateDisplay() method.

The connection between the two classes is handled automatically.

The following diagram maps out the memory used by the example.

Outer Class/Inner Class Memory Map

Instantiating an Inner Class Instance from within the Enclosing Class

An inner class instance may be directly instantiated from code in the enclosing class, without any special syntax:

Syntax

[modifiers] class OuterClassName {
	code 
               [modifiers] class InnerClassName {
		code
	}
	public void someMethod() {
		InnerClassName variable = new InnerClassName();
	}
}

Such an instance is automatically associated with the enclosing class instance that instantiated it.

Code Sample:

Java-InnerClasses/Demos/Inner1.java
public class Inner1 {
	public static void main(String[] args) {
		new MyOuter(1, 2);
	}
}

Code Explanation

This code simply creates an instance of the outer class, MyOuter.

The MyOuter constructor creates an instance of MyInner as mentioned earlier.

Inner Classes Referenced from Outside the Enclosing Class

If the access term for the inner class definition is public (or the element is accessible at package access or protected level to the other class), then other classes can hold references to one or more of these inner class objects.

  • If the inner class is static, then it can exist without an outer class object, otherwise any inner class object must belong to an outer class instance.

For code that is not in the outer class, a reference to a static or non-static inner class object must use the outer class name, a dot, then the inner class name:

Syntax

 
               OuterClassName.InnerClassName innerClassVariable
            

If the inner class has an accessible constructor, then you can instantiate one from outside of the enclosing class, although the syntax is ugly, and there is rarely a need for this capability.

To create a non-static inner class object from outside the enclosing class, you must attach it to an outer class instance.

Syntax

 
                  outerClassVariable.new InnerClassName(arguments)

For this purpose the new operator is a binary operator - it creates a new object of the type on its right belonging to the object on its left.

Code Sample:

Java-InnerClasses/Demos/Inner2.java
public class Inner2 {
  public static void main(String[] args) {
    MyOuter mo;
    MyOuter.MyInner momi;
    mo = new MyOuter(1, 2);
    momi = mo.new MyInner(102);
    momi.publicDisplay();
  }
}

Code Explanation

In the main method, the variable momi for the inner class instance is typed as MyInner.MyOuter.

It is populated by instantiating it attached to mo, using mo.new MyInner(102).

It is generally recommended to avoid this syntax, and rely instead on outer class code to instantiate the inner class objects. Making the inner constructors private or protected will enforce this practice (generally protected is better, since that would allow extensions of the outer class to also create inner class objects).

Note that we can access any public elements of the inner class instance, as in momi.publicDisplay();

Referencing the Outer Class Instance from the Inner Class Code

If inner class code needs a reference to the outer class instance to which it is attached, use the name of the outer class, a dot, and this. Remember that if there is no name conflict, there is no need for any special syntax.

For code in MyInner to obtain a reference to its MyOuter:

MyOuter.this

static Inner Classes

An inner class may be marked as static.

A static inner class my be instantiated without an instance of the outer class. Note that:

  • static members of the outer class are visible to the inner class, no matter what their access level.
  • Non-static members of the outer class are not available, since there is no instance of the outer class from which to retrieve them.

To create a static inner class object from outside the enclosing class, you must still reference the outer class name

Syntax

new OuterClassName.InnerClassName(arguments)

An inner class may not have static members unless the inner class is itself marked as static.

Code Sample:

Java-InnerClasses/Demos/StaticInnerTest.java
class StaticOuter {
  public StaticInner createInner() {
    return new StaticInner();
  }

  static class StaticInner {
    public static void display() {
      System.out.println("StaticOuter.Inner display method");
    } 
  }
}

class StaticInnerTest  {
  public static void main(String[] args) {
    
    new StaticOuter.StaticInner().display();
    
    StaticOuter so = new StaticOuter();
    
    //so.new StaticInner().display();
    
    so.createInner().display();

    
  }
}

Code Explanation

We have a class StaticOuter that declares a static inner class StaticInner. StaticOuter has a method that will create instances of StaticInner. But, StaticInner also has a public constructor. Note that:

  • We can directly instantiate a StaticOuter.StaticInner object without an outer class instance.
  • Code for a StaticOuter can create a StaticInner, but the inner class object has no attachment to the outer class object that created it.
  • Note the commented out line; you cannot create a static inner class instance attached to an instance of its enclosing class.

Better Practices for Working with Inner Classes

It is easiest if inner-class objects can always be instantiated from the enclosing class object. You can create a factory method to accomplish this.

Code Sample:

Java-InnerClasses/Demos/FactoryInnerOuter.java
class FactoryOuter {
  FactoryInner[] fi = new FactoryInner[3];
  protected int lastIndex = 0;
  private int x = 0;
  public FactoryOuter(int x) {
    this.x = x;
  }
  public int getX() {
    return x;
  }
  public void addInner(int y) {
    if (lastIndex < fi.length) {
      fi[lastIndex++] = new FactoryInner(y);
    } 
    else throw new RuntimeException("FactoryInner array full");
  }
  public void list() {
    for (int i = 0; i < fi.length; i++) {
      System.out.print("I can see into the inner class where y = " + 
                       fi[i].y + " or call display: ");
      fi[i].display();      
    }
  }
  public class FactoryInner {
    private int y;
    protected FactoryInner(int y) {
      this.y = y;
    }
    public void display() {
      System.out.println("FactoryInner x =  " + x + " and y = " + y);
    }
  }
}
public class FactoryInnerOuter {
  public static void main(String[] args) {
    FactoryOuter fo = new FactoryOuter(1);
    fo.addInner(101);
    fo.addInner(102);
    fo.addInner(103);
    fo.list();
    //fo.addInner(104);
  }
}

Code Explanation

For convenience, this file contains both the main class and the FactoryOuter class (with package access). Note that:

  • An instance of FactoryOuter contains a three element array of FactoryInner objects.
  • The addInner method instantiates a FactoryInner object and adds it to the array (note that is still automatically associated with the FactoryOuter instance by the JVM, but we need our own mechanism for keeping track of the inner class instances we create).
    • A better approach would be to use one of the collections classes instead of an array, to avoid running out of room in the array

This is exactly the sort of thing that happens when you obtain an iterator from a collection class. In order to successfully navigate what is most likely a complex internal structure, the object will need access to the private elements. So, an inner class is used, but all you need to know about the object is that it implements the Iterator interface.

Let's look at how we might apply these concepts to our "Payroll" program:

Code Sample:

Java-InnerClasses/Demos/PayrollInnerClass/employees/Employee.java
package employees;
import finance.TransactionException;

public class Employee {
 
  private static int nextId = 1;
  
  public static void setNextId(int nextId) {
    Employee.nextId = nextId;
  }

  private int id = nextId++;
  private String firstName;
  private String lastName;
  private double payRate;

  private double ytdPay;
  private Payment[] payments = new Payment[12]; 
  private int paymentCount = 0;  
 
  public Employee() { }

  public Employee(String firstName, String lastName, double payRate) {
    setFirstName(firstName);
    setLastName(lastName);
    setPayRate(payRate);
  }
  
  public static int getNextId() {
    return nextId;
  }
  
  public int getId() { return id; }

  public String getFirstName() { return firstName; }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  
  public String getLastName() { return lastName; }
  
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public String getFullName() { return firstName + " " + lastName; }

  public double getPayRate() { return payRate; }
  
  public void setPayRate(double payRate)
        throws IllegalArgumentException {
    if (payRate >= 0) {
        this.payRate = payRate;
      }
    else {
      throw new IllegalArgumentException(
            "Pay amount: " + payRate + " must not be negative");
    }
  }

  public double getYtdPay() { return ytdPay; }
  
  public Payment createPayment() {
    Payment p = new Payment(payRate);
    payments[paymentCount++] = p;
    return p;
  }

  public void printPaymentHistory() {
    for (Payment p : payments) {
      System.out.println(p);
    }
  }
  
  public class Payment {
    private double amount;
    private boolean posted;
    
    public Payment(double amount) {
      this.amount = amount;
    }

    public boolean process() throws TransactionException {
      if (!posted) {
        ytdPay += amount;
        posted = true;
        System.out.println(getFullName() + " paid " + amount);
        return true;
      } else {
        throw new TransactionException("Transaction already processed");
      }
    }
    
    public String toString() {
      return getFullName() + " payment of " + amount;
    }
    
  } 
}

Code Explanation

Payment is an inner class to a simplified Employee and, as an inner class, has free access to all private elements of Employee. Unlike a standalone payment class, this class can retrieve the employee name from the outer class instance. We also use this access to defer updating the year-to-date amounts until the payment is posted, via the process method.

To get this degree of interaction between two separate classes would be difficult, since it would mean that either:

  1. The ability to update ytdPay would have to be publicly available.
  2. Employee and Payment would have to be in the same package, with updating ytdPay achieved by using package access.

Note that we have also separated the concepts of creating a payment from actually posting it. This gives us better control over transactions - note that a payment cannot be processed twice.

Code Sample:

Java-InnerClasses/Demos/PayrollInnerClass/Payroll.java
import employees.*;
import finance.*;

public class Payroll {
  public static void main(String[] args) {

    Employee.setNextId(22);
    Employee e = new Employee("John", "Doe", 6000.0);
    
    // loop to pay each month
    for (int month = 0; month < 12; month++) {
      Employee.Payment p = e.createPayment();
      try {
        p.process();
        
        // HR error causes attempt to process June paycheck twice
        if (month == 5) p.process();
      }
      catch (TransactionException te) {
        System.out.println(te.getMessage());
      }
      System.out.println("Ytd pay: " + e.getYtdPay());
    }     
    
    System.out.println("Employee Payment History:");
    
    e.printPaymentHistory();
  }
  
}

Code Explanation

We have only one employee for simplicity. As we loop for each month, a payment is created for each. We try to process the June payment twice (remember that the array is zero-based, so January is month 0; this matches the behavior of the java.util.Date class) . The second attempt to process the payment should throw an exception which our catch block handles.

We retrieve and print the year-to-date pay each time we process a payment.

At the end, we have the Employee object print the entire payment history created by our calls to the inner class' process method.

In the next demo, we'll look at how we could enhance our "Payroll" program further, using an inner class that implements an interface:

Code Sample:

Java-InnerClasses/Demos/PayrollInnerClassInterface/employees/Employee.java
package employees;
import finance.*;

public class Employee {
 
  private static int nextId = 1;
  
  public static void setNextId(int nextId) {
    Employee.nextId = nextId;
  }

  private int id = nextId++;
  private String firstName;
  private String lastName;
  private double payRate;

  private double ytdPay;
  private Payment[] payments = new Payment[12]; 
  private int paymentCount = 0;  
  
  public Employee() { }

  public Employee(String firstName, String lastName, double payRate) {
    setFirstName(firstName);
    setLastName(lastName);
    setPayRate(payRate);
  }
  
  public static int getNextId() {
    return nextId;
  }
  
  public static void setNextId(int nextId) {
    Employee.nextId = nextId;
  }
  
  public int getId() { return id; }

  public String getFirstName() { return firstName; }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  
  public String getLastName() { return lastName; }
  
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public String getFullName() { return firstName + " " + lastName; }

  public double getPayRate() { return payRate; }
  
  public void setPayRate(double payRate)
        throws IllegalArgumentException {
    if (payRate >= 0) {
        this.payRate = payRate;
      }
    else {
      throw new IllegalArgumentException(
            "Pay amount: " + payRate + " must not be negative");
    }
  }

  public double getYtdPay() { return ytdPay; }
  
  public Payment createPayment() {
    Payment p = new Payment(payRate);
    payments[paymentCount++] = p;
    return p;
  }

  public void printPaymentHistory() {
    for (Payment p : payments) {
      System.out.println(p);
    }
  }
  
  public class Payment implements Payable {
    private double amount;
    private boolean posted;
    
    public Payment(double amount) {
      this.amount = amount;
    }

    public boolean process() throws TransactionException {
      if (!posted) {
        ytdPay += amount;
        posted = true;
        System.out.println(getFullName() + " paid " + amount);
        return true;
      } else {
        throw new TransactionException("Transaction already processed");
      }
    }
    
    public String toString() {
      return getFullName() + " payment of " + amount;
    }
    
  } 
}

Code Explanation

This code goes one step further to create a Payment inner class that implements the Payable interface.

Code Sample:

Java-InnerClasses/Demos/PayrollInnerClassInterface/Payroll.java
import employees.*;
import finance.*;

public class Payroll {
  public static void main(String[] args) {

    Employee.setNextId(22);
    Employee e = new Employee("John", "Doe", 6000.0);
    
    // loop to pay each month
    for (int month = 0; month < 12; month++) {
      Payable p = e.createPayment();
      try {
        p.process();
        
        // HR error causes attempt to process June paycheck twice
        if (month == 5) p.process();
      }
      catch (TransactionException te) {
        System.out.println(te.getMessage());
      }
      System.out.println("Ytd pay: " + e.getYtdPay());
    }     
    
    System.out.println("Employee Payment History:");
    
    e.printPaymentHistory();
  }
  
}

Code Explanation

The only difference here is that we declare the variable holding the payments as Payable, hiding the fact that it is an inner class.

Anonymous Inner Classes

An anonymous inner class, one with no class name, may be defined at any point where an object reference is needed (usually when passing an object to a function).

The class may implement an interface. The function would be expecting to receive an object of the interface type.

  • Syntax

    new InterfaceToImplement () {
    properties and interface methods
    }

Or, the class may extend another class. The function would be expecting to receive an object of that type.

  • Syntax

    new ClassToExtend () {
    properties and interface methods
    }

    Syntax

    new ClassToExtend (parameter list matching base class constructor) {
    properties and overridden methods
    }
  • the syntax is: new () { }

It becomes a one-of-a-kind object, since there is no class name that you can use to create another instance.

Note that it would not make sense to declare any public methods not defined in the interface or base class, since the variable used to reference this object will be typed as the interface or base class, and therefore have no way to know about the additional methods.

This code can be written any place an object is expected, for example, inside a function call's parentheses, where you would normally put the object reference to be passed.

The new class cannot define constructors, but, for an anonymous derived class, parameters can be passed to the new object that match a constructor defined in the base class.

Anonymous classes may not be marked as static, since they would only exist tied to an instance of the creating class.

Anonymous Interface Example

This example uses the Printable interface we created earlier.

Code Sample:

Java-InnerClasses/Demos/AnonymousInterfaceTest.java
public class AnonymousInterfaceTest {
AnonymousInterfaceTest() {
go(  
new Printable() {
private String data = new String("XYZ"); 
public void printAll() {
System.out.println("Data is: " + data);
}
} 
);
}  
public void go(Printable x) {
x.printAll();
}
public static void main(String[] args) {
new AnonymousInterfaceTest();
}
}

Code Explanation

main creates a new instance of AnonymousInterfaceTest.

AnonymousInterfaceTest has a method called go(Printable x) that accepts a parameter that is a Printable object. It calls that object's printAll() method

The constructor calls go and passes it an instance of a newly defined class that implements Printable.

Anonymous classes that implement an interface are most often used in GUI programming to create a specific event handler that is customized to one item such as a button, since the action to be performed is specific to that button.

Anonymous Derived Class Example

Code Sample:

Java-InnerClasses/Demos/AnonymousInheritanceTest.java
public class AnonymousInheritanceTest {

AnonymousInheritanceTest (int x) {
go(  
new BaseClassForAnonymous(x) {
public void print() {
System.out.println("AnonymousDerivedClass x = " + x);
}
} 
);
}  

public void go(BaseClassForAnonymous bc) {
bc.print();
}

public static void main(String[] args) {
new AnonymousInheritanceTest(5);
}
}

class BaseClassForAnonymous {

protected int x;

public BaseClassForAnonymous(int x) {
this.x = x;
}

public void print() {
System.out.println("BaseClassForAnonymous x = " + x);
}
}

Code Explanation

This anonymous class is created by extending an existing class, BaseClassForAnonymous.

In this case, the newly defined class extends the base class and overrides its print() method. Note the parameter passed to the constructor during the class definition

Callbacks

You can create an inner class to be used for a callback in a situation where you have private data members, and wish to protect them to the extent that:

  • You would not want to create a public set method.
  • You can't just pass a reference to the member to the outside, because
    • The member is a primitive, or
    • You need a complex method to set the value instead of just passing a reference to it.

The callback is achieved by:

  • The outer class object instantiating an inner class object that includes a set method for the data member.
  • Then passing that object to a method of some other class, or as a return value.

Code Sample:

Java-InnerClasses/Demos/CallbackTest.java
[class CallbackOwner {
private int x = 0;
public int getX() {
return x;
}
public CallbackObject getCBO() {
return new CallbackObject();
}
public class CallbackObject {
public void setX(int x) {
CallbackOwner.this.x = x;
}
}
}

public class CallbackTest {
public static void main(String args[]) {
CallbackOwner c= new CallbackOwner();
CallbackOwner.CallbackObject cbo = c.getCBO();
System.out.println("x is " + c.getX());
cbo.setX(10);
System.out.println("x is now " + c.getX());
}
}

Code Explanation

We use class CallbackOwner to demonstrate a callback. Our first call to c.getX() returns 0; after the call cbo.setX(10), the next call to c.getX() returns 10.

Callbacks Using Interfaces

A cleaner approach would be to have the inner class implement an interface, so that the variable in the main class could be an interface variable - this removes any inner class-related syntax from the main class.

Code Sample:

Java-InnerClasses/Demos/CallbackInterfaceTest.java
interface CallbackInterface {
public void setX(int x);
}

class CallbackInterfaceOwner {
private int x = 0;
public int getX() {
return x;
}
public CallbackInterfaceObject getCBIO() {
return new CallbackInterfaceObject();
}
public class CallbackInterfaceObject
implements CallbackInterface {
public void setX(int x) {
CallbackInterfaceOwner.this.x = x;
}
}
}

public class CallbackInterfaceTest {
public static void main(String args[]) {
CallbackInterfaceOwner c= new CallbackInterfaceOwner();
CallbackInterface cbi = c.getCBIO();
System.out.println("x is " + c.getX());
cbi.setX(10);
System.out.println("x is now " + c.getX());
}
}

Code Explanation

We do a similar thing here, but this time our class CallbackInterfaceObject implements interface CallbackInterface to effect the callback.

An anonymous inner class, one with no class name, may be defined at any point where an object reference is needed (usually when passing an object to a function).

The class may implement an interface. The function would be expecting to receive an object of the interface type.

  • Syntax

    new InterfaceToImplement () {
    properties and interface methods
    }

Or, the class may extend another class. The function would be expecting to receive an object of that type.

  • Syntax

    new ClassToExtend () {
    properties and interface methods
    }

    Syntax

    new ClassToExtend (parameter list matching base class constructor) {
    properties and overridden methods
    }
  • the syntax is: new () { }

It becomes a one-of-a-kind object, since there is no class name that you can use to create another instance.

Note that it would not make sense to declare any public methods not defined in the interface or base class, since the variable used to reference this object will be typed as the interface or base class, and therefore have no way to know about the additional methods.

This code can be written any place an object is expected, for example, inside a function call's parentheses, where you would normally put the object reference to be passed.

The new class cannot define constructors, but, for an anonymous derived class, parameters can be passed to the new object that match a constructor defined in the base class.

Anonymous classes may not be marked as static, since they would only exist tied to an instance of the creating class.

Anonymous Interface Example

This example uses the Printable interface we created earlier.

Code Sample:

Java-InnerClasses/Demos/AnonymousInterfaceTest.java
public class AnonymousInterfaceTest {
AnonymousInterfaceTest() {
go(  
new Printable() {
private String data = new String("XYZ"); 
public void printAll() {
System.out.println("Data is: " + data);
}
} 
);
}  
public void go(Printable x) {
x.printAll();
}
public static void main(String[] args) {
new AnonymousInterfaceTest();
}
}

Code Explanation

main creates a new instance of AnonymousInterfaceTest.

AnonymousInterfaceTest has a method called go(Printable x) that accepts a parameter that is a Printable object. It calls that object's printAll() method

The constructor calls go and passes it an instance of a newly defined class that implements Printable.

Anonymous classes that implement an interface are most often used in GUI programming to create a specific event handler that is customized to one item such as a button, since the action to be performed is specific to that button.

Anonymous Derived Class Example

Code Sample:

Java-InnerClasses/Demos/AnonymousInheritanceTest.java
public class AnonymousInheritanceTest {

AnonymousInheritanceTest (int x) {
go(  
new BaseClassForAnonymous(x) {
public void print() {
System.out.println("AnonymousDerivedClass x = " + x);
}
} 
);
}  

public void go(BaseClassForAnonymous bc) {
bc.print();
}

public static void main(String[] args) {
new AnonymousInheritanceTest(5);
}
}

class BaseClassForAnonymous {

protected int x;

public BaseClassForAnonymous(int x) {
this.x = x;
}

public void print() {
System.out.println("BaseClassForAnonymous x = " + x);
}
}

Code Explanation

This anonymous class is created by extending an existing class, BaseClassForAnonymous.

In this case, the newly defined class extends the base class and overrides its print() method. Note the parameter passed to the constructor during the class definition

Callbacks

You can create an inner class to be used for a callback in a situation where you have private data members, and wish to protect them to the extent that:

  • You would not want to create a public set method.
  • You can't just pass a reference to the member to the outside, because
    • The member is a primitive, or
    • You need a complex method to set the value instead of just passing a reference to it.

The callback is achieved by:

  • The outer class object instantiating an inner class object that includes a set method for the data member.
  • Then passing that object to a method of some other class, or as a return value.

Code Sample:

Java-InnerClasses/Demos/CallbackTest.java

Code Explanation

We use class CallbackOwner to demonstrate a callback. Our first call to c.getX() returns 0; after the call cbo.setX(10), the next call to c.getX() returns 10.

Callbacks Using Interfaces

A cleaner approach would be to have the inner class implement an interface, so that the variable in the main class could be an interface variable - this removes any inner class-related syntax from the main class.

Code Sample:

Java-InnerClasses/Demos/CallbackInterfaceTest.java

Code Explanation

We do a similar thing here, but this time our class CallbackInterfaceObject implements interface CallbackInterface to effect the callback.

Method Inner Classes

A class may be defined within a method. Note that:

  • Because it is within a method, it has access to local variables for that method, as long as those variables are marked as final.
  • They are required to be final because the inner class object might persist after the method is finished, so that there would be no place to write a value back to.
  • Keep in mind, however, that a reference variable declared to be final means only that the reference cannot be changed; the contents of the object it points to may still be modified - in the example below a final Random object reference is used to generate an ongoing series of values.

A method inner class may not be marked as static, since it will only exist if there is an instance of the creating class (if the class is defined in a static method, the method is still not marked as static).

Note that anonymous inner classes are usually method inner classes, unless they are declared in a property initializer.

Code Sample:

Java-InnerClasses/Demos/MethodLocalTest.java
public class AnonymousInheritanceTest {

  AnonymousInheritanceTest (int x) {
    go(  
       new BaseClassForAnonymous(x) {
         public void print() {
           System.out.println("AnonymousDerivedClass x = " + x);
         }
       } 
       );
  }  

  public void go(BaseClassForAnonymous bc) {
    bc.print();
  }

  public static void main(String[] args) {
    new AnonymousInheritanceTest(5);
  }
}

class BaseClassForAnonymous {

  protected int x;

  public BaseClassForAnonymous(int x) {
    this.x = x;
  }

  public void print() {
    System.out.println("BaseClassForAnonymous x = " + x);
  }
}

Code Explanation

A class may be defined within a method. Note that:

A method inner class may not be marked as static, since it will only exist if there is an instance of the creating class (if the class is defined in a static method, the method is still not marked as static).

Note that anonymous inner classes are usually method inner classes, unless they are declared in a property initializer.

Code Sample:

Java-InnerClasses/Demos/MethodLocalTest.java
public class MethodLocalTest {
        
  public Printable p = null;
  
  MethodLocalTest() {
    final java.util.Random r = new java.util.Random();
          
    class InnerPrintable implements Printable {
      private String data = new String("WXYZ"); 
      public void printAll() {
        System.out.println("Data is: " + data + " " +
                           r.nextInt(10) );
      }
    }
    p = new InnerPrintable();
  }  
  
 public void go(Printable x) {
    x.printAll();
  }
  public static void main(String[] args) {
    MethodLocalTest a = new MethodLocalTest();
    a.p.printAll();
    a.p.printAll();
    a.p.printAll();
    a.p.printAll();
    a.p.printAll();
  }
}

Enums

The enum element provides a set of predefined constants for indicating a small set of mutually exclusive values or states.

Why Another Syntax Element for a Set of Constants?

Before enums, there were other ways to handle this kind of situation - but the other approaches all had some sort of flaw, particularly as involves type-safety.

Java enums provide a type-safe way of creating a set of constants, since they are defined as a class, and therefore are a type of data.

A disadvantage to this approach is that the set of values is written into the code. For sets of values that may change, this would require recompiling the code, and would invalidate any serialized instances of the enum class. For example, if we offered a choice of benefits plans to our employees, the set of available plans would not be a good candidate for an enum, since it is likely that the set of available plans would eventually change.

Defining an enum Class

To create a simple enum class:

  1. Declare like an ordinary class, except using the keyword enum instead of class.
  2. Within the curly braces, supply a comma-separated list of names, ending in a semicolon.

One instance of the enum class will be created to represent each item you listed, available as a static field of the class, using the name you supplied which will be the individual values. Each instance can provide an integral value, with sequential indexes starting at 0, in the order that the names were defined - there is no way to change this, but there is a route to get specific values which have a complex internal state.

Syntax

public enum EnumName {
	value1, value2, value3, . . . ;
}
public enum Alignment { left, right, center; }

There will be three instances of the class created: Alignment.left, Alignment.right, and Alignment.center. An Alignment type variable can hold any of these three values.

Enums automatically extend the Enum class from the API, and they inherit several useful methods:

There are also several other methods that will be present, although they are not listed in the documentation for Enum.

The reason for the last two methods not being in the documentation has to do with generics and type erasure - the methods cannot be declared in the Enum base class in a way that would allow the use of the as-yet unknown subclass.

Individual values from the set may be accessed as static elements of the enum class. The JVM will instantiate exactly one instance of each value from the set. Therefore, they can be used in comparisons with ==, or in switch statements (using the equals method is preferred to ==, since it will serve as a reminder that you are dealing with true objects, not integers).

Although enums may be top-level classes, they are often created as inner classes, as in the following example, where the concept of the enum is an integral part of a new BookWithEnum class. When used as an inner class, they are automatically static, so that an instance of an inner enum does not have access to instance elements of the enclosing class.

Code Sample:

Java-InnerClasses/Demos/BookWithEnum.java
public class BookWithEnum {
  private int itemCode;
  private String title;
  private double price;
  private Category category;
  
  public enum Category { required, supplemental, optional, unknown };
  
  public BookWithEnum(
        int itemCode, String title, 
        double price, Category category) {
    setItemCode(itemCode);
    setTitle(title);
    setPrice(price);
    setCategory(category);
  }
  public BookWithEnum(String title) {
    setItemCode(0);
    setTitle(title);
    setPrice(0.0);
    setCategory(Category.unknown);
  }
  public int getItemCode() {
    return itemCode;
  }
  public void setItemCode (int itemCode) {
    if (itemCode > 0) this.itemCode = itemCode; 
  }
  public String getTitle() {
    return title;
  }
  public void setTitle (String title) {
    this.title = title;
  }
  public void setPrice(double price) {
    this.price = price;
  }
  public double getPrice() {
    return price;
  }
  public void setCategory(Category category) {
    this.category = category;
  }
  public void setCategory(String categoryName) {
    this.category = Category.valueOf(categoryName);
  }
  public Category getCategory() {
    return category;
  }
  public void display() {
    System.out.println(itemCode + " " + title + ": " + category +
          ", Price: $" + price);
  }
}

Code Explanation

The Category enum is defined as an inner class to BookWithEnum. The full names of the complete set of values are: BookWithEnum.Category.required, BookWithEnum.Category.supplemental, BookWithEnum.Category.optional, and BookWithEnum.Category.unknown. From within the BookWithEnum class, they may be accessed as: Category.required, Category.supplemental, Category.optional, and Category.unknown.

We set the category for a book constructed without one as Category.unknown, and provide methods to get the value, and to set it with either an enum object or from a string.

Note that enums may be used in switch statements - for the cases you use only the short name for the value.

More Complex Enums

Enums are more than just a set of integer constants. They are actually a set of unique object instances, and, as objects, can have multiple fields. So, an enum is a class with a fixed number of possible instances, each with it's own unique state, and each of the possible instances is created automatically and stored as static field under the same name. (In design pattern terms, an enum is a Flyweight - a class where only a limited number of fixed states exist.)

To create a more complex enum class:

  1. Declare as before.
  2. Declare any additional fields and accessor methods as with a regular class. While you can actually write mutator methods to create what is called a mutable enum, this practice is strongly discouraged.
  3. Write one constructor.
  4. Within the curly braces, again supply a comma-separated list of names, which will be the individual values, but this time with a parameter list. The enum values will be constructed with the data you provide.

Code Sample:

Java-InnerClasses/Demos/UsedBookWithEnum.java
public class UseBookWithEnum {
  public static void main(String[] args) {
    BookWithEnum b = new BookWithEnum(
          5011, "Fishing Explained", 25.0, 
          BookWithEnum.Category.required);
    b.display();
    System.out.println();
    
    b.setCategory(BookWithEnum.Category.supplemental);
    b.display();
    System.out.println();
    
    b.setCategory("optional");
    b.display();
    System.out.println();
    
    BookWithEnum.Category category = b.getCategory();
    switch (category) {
    case required: 
      System.out.println(b.getTitle() + " is required.");
      break;
    case optional: 
      System.out.println(b.getTitle() + " is optional.");
      break;
    case supplemental: 
      System.out.println(b.getTitle() + " is a supplemental book.");
      break;
    case unknown: 
      System.out.println("Category for " + b.getTitle() + 
          " is not known at this time."); break;
    }
    System.out.println();
    
    StringBuilder categoryList = new StringBuilder("Categories:\n");
    for (BookWithEnum.Category cat : BookWithEnum.Category.values()) {
      categoryList.append("  ").append(cat.name()).append('\n');
    }
    System.out.println(categoryList); 
  }
}

Code Explanation

This enum contains a field, discount, with a get method, but no set method. The discount is set through the constructor, which is invoked at the time the instances are defined. Any of the methods may be called at any time on an Condition instance, such as the getDiscountedPrice(UsedBookWithEnum) method.