Inner classes

index
INTERMEDIATE

There are four types of inner classes: member, static member, local, and anonymous.

A member class is defined at the top level of the class. It may have the same access modifiers as variables (public, protected, package, static, final), and is accessed in much the same way as variables of that class.

public class OuterClass {
    int outerVariable = 100;
 
    class MemberClass {
        int innerVariable = 20;
         
        int getSum(int parameter) {
            return innerVariable +  outerVariable + parameter;
        }       
    }
     
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        MemberClass inner = outer.new MemberClass(); 
        System.out.println(inner.getSum(3));
        outer.run();
    }
     
    void run() {
        MemberClass localInner = new MemberClass();
        System.out.println(localInner.getSum(5));
    }
}

A static member class is defined like a member class, but with the keyword static. Despite its position inside another class, a static member class is actually an "outer" class--it has no special access to names in its containing class. To refer to the static inner class from a class outside the containing class, use the syntax OuterClassName.InnerClassName. A static member class may contain static fields and methods.

public class OuterClass {
    int outerVariable = 100;
    static int staticOuterVariable = 200;
 
    static class StaticMemberClass {
        int innerVariable = 20;
         
        int getSum(int parameter) {
            // Cannot access outerVariable here
            return innerVariable + staticOuterVariable + parameter;
        }       
    }
     
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        StaticMemberClass inner = new StaticMemberClass(); 
        System.out.println(inner.getSum(3));
        outer.run();
    }
     
    void run() {
        StaticMemberClass localInner = new StaticMemberClass();
        System.out.println(localInner.getSum(5));
    }
}

A local inner class is defined within a method, and the usual scope rules apply to it. It is only accessible within that method, therefore access restrictions (public, protected, package) do not apply. However, because objects (and their methods) created from this class may persist after the method returns, a local inner class may not refer to parameters or non-final local variables of the method.

public class OuterClass {
    int outerVariable = 10000;
    static int staticOuterVariable = 2000;
     
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        System.out.println(outer.run());
    }
     
    Object run() {
        int localVariable = 666;
        final int finalLocalVariable = 300;
         
        class LocalClass {
            int innerVariable = 40;
             
            int getSum(int parameter) {
                // Cannot access localVariable here
                return outerVariable + staticOuterVariable + 
                       finalLocalVariable + innerVariable + parameter;
            }       
        }
        LocalClass local = new LocalClass();
        System.out.println(local.getSum(5));
        return local;
    }
}

An anonymous inner class is one that is declared and used to create one object (typically as a parameter to a method), all within a single statement.

An anonymous inner class may extend a class:

new SuperClass(parameters){ class body }

Here, SuperClass is not the name of the class being defined, but rather the name of the class being extended. The parameters are the parameters to the constructor for that superclass.

An anonymous inner class may implement an interface:

new Interface(){ class body }

Because anonymous inner classes are almost always used as event listeners, the example below uses an anonymous inner class as a button listener.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
 
public class OuterClass extends JFrame {
     
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        JButton button = new JButton("Don't click me!");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                System.out.println("Ouch!");
            }
        });
        outer.add(button);
        outer.pack();
        outer.setVisible(true);
    }
}

STYLE

Because anonymous inner classes occur within a method, they break up the flow and add several lines to the method. Consequently, the actual code within an anonymous inner class should be kept very short--usually a single method call.