Inner Classes (Nested Classes)

Lesson 0013 — 35 min read

An Inner Class (or Nested Class) is a class defined inside another enclosing class or function. They help logically group helper types, improve encapsulation, and restrict helper visibility to where it matters most.

Overview: Inner vs Nested Classes

While Java distinguishes sharply between static nested classes (no outer instance reference) and non-static inner classes (holds an implicit outer instance reference), C++ and Python treat nested classes as naturally independent types scoped within the outer class namespace.

There are 4 main categories of inner / nested class patterns:

1. Static Nested Classes

A static nested class does not require an instance of the enclosing class. It can access outer static members directly, but cannot access outer instance members without an explicit object reference.

class OuterClass {
    static int staticVar = 100;

    // Static Nested Class
    static class StaticNestedClass {
        void display() {
            System.out.println("Static variable: " + staticVar);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass.StaticNestedClass nestedObj = new OuterClass.StaticNestedClass();
        nestedObj.display(); // Output: Static variable: 100
    }
}
#include <iostream>
using namespace std;

class OuterClass {
public:
    static int staticVar;

    // Nested class (naturally independent in C++)
    class NestedClass {
    public:
        void display() {
            cout << "Static variable: " << OuterClass::staticVar << "\n";
        }
    };
};

int OuterClass::staticVar = 100;

int main() {
    OuterClass::NestedClass nestedObj;
    nestedObj.display(); // Output: Static variable: 100
    return 0;
}
class OuterClass:
    static_var = 100

    # Nested class (independent by default in Python)
    class StaticNestedClass:
        def display(self):
            print("Static variable:", OuterClass.static_var)

def main():
    nested_obj = OuterClass.StaticNestedClass()
    nested_obj.display() # Output: Static variable: 100

if __name__ == "__main__":
    main()

2. Non-Static Inner Classes

A non-static inner class is associated with an instance of the outer class.

class OuterClass {
    int instanceVar = 42;

    // Non-static Inner Class
    class InnerClass {
        void display() {
            // Implicit access to outer instance variable
            System.out.println("Instance variable: " + instanceVar);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass outerObj = new OuterClass();
        OuterClass.InnerClass innerObj = outerObj.new InnerClass();
        innerObj.display(); // Output: Instance variable: 42
    }
}
#include <iostream>
using namespace std;

class OuterClass {
public:
    int instanceVar = 42;

    // Nested class storing explicit reference to outer instance
    class InnerClass {
        OuterClass &outer;
    public:
        InnerClass(OuterClass &outerRef) : outer(outerRef) {}

        void display() {
            cout << "Instance variable: " << outer.instanceVar << "\n";
        }
    };
};

int main() {
    OuterClass outerObj;
    OuterClass::InnerClass innerObj(outerObj);
    innerObj.display(); // Output: Instance variable: 42
    return 0;
}
class OuterClass:
    def __init__(self):
        self.instance_var = 42

    class InnerClass:
        def __init__(self, outer):
            self.outer = outer

        def display(self):
            print("Instance variable:", self.outer.instance_var)

def main():
    outer_obj = OuterClass()
    inner_obj = OuterClass.InnerClass(outer_obj)
    inner_obj.display() # Output: Instance variable: 42

if __name__ == "__main__":
    main()

3. Local Inner Classes (Classes Inside Functions)

Local inner classes are declared inside a method or function block and are only visible within that method's scope.

class OuterClass {
    void outerMethod() {
        int localVar = 10; // Effectively final

        // Local Inner Class
        class LocalInnerClass {
            void display() {
                System.out.println("Local variable: " + localVar);
            }
        }

        LocalInnerClass localInner = new LocalInnerClass();
        localInner.display(); // Output: Local variable: 10
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass outerObj = new OuterClass();
        outerObj.outerMethod();
    }
}
#include <iostream>
using namespace std;

class OuterClass {
public:
    void outerMethod() {
        int localVar = 10;

        // Local class inside a method
        class LocalInnerClass {
            int captured;
        public:
            LocalInnerClass(int x) : captured(x) {}

            void display() {
                cout << "Local variable: " << captured << "\n";
            }
        };

        LocalInnerClass localInner(localVar);
        localInner.display(); // Output: Local variable: 10
    }
};

int main() {
    OuterClass outerObj;
    outerObj.outerMethod();
    return 0;
}
class OuterClass:
    def outer_method(self):
        local_var = 10

        # Local class inside a method
        class LocalInnerClass:
            def __init__(self, x):
                self.captured = x

            def display(self):
                print("Local variable:", self.captured)

        local_inner = LocalInnerClass(local_var)
        local_inner.display() # Output: Local variable: 10

def main():
    outer_obj = OuterClass()
    outer_obj.outer_method()

if __name__ == "__main__":
    main()

4. Anonymous Inner Classes & Lambdas

Anonymous inner classes have no name and are instantiated at the point of declaration for one-time use (e.g., event listeners or single-use interface implementations).

In modern C++ and Python, one-time behavior is almost universally implemented using Lambdas or inline function objects rather than verbose anonymous class structures.

abstract class Greeting {
    abstract void sayHello();
}

public class Main {
    public static void main(String[] args) {
        // Anonymous Inner Class
        Greeting greeting = new Greeting() {
            void sayHello() {
                System.out.println("Hello, World!");
            }
        };

        greeting.sayHello(); // Output: Hello, World!
    }
}
#include <iostream>
using namespace std;

int main() {
    // Lambda expression (modern C++ anonymous function)
    auto sayHello = []() {
        cout << "Hello, World!\n";
    };

    sayHello(); // Output: Hello, World!
    return 0;
}
def main():
    # Lambda expression (anonymous inline function)
    say_hello = lambda: print("Hello, World!")

    say_hello() # Output: Hello, World!

if __name__ == "__main__":
    main()

Comparison Across Languages

Pattern Java C++ Python
Static Nested Declared with static; no outer instance reference Naturally independent nested class; scoped type Nested class by default; scoped namespace
Non-Static Inner Implicit outer reference (OuterClass.this) Explicit reference/pointer to outer stored in nested class Explicit outer object reference passed into __init__
Local Class Captures effectively final local method variables Defined in function scope; manual constructor capture required Defined in method scope; manual constructor capture recommended
Anonymous / One-time Anonymous inner class or Lambda expressions Lambda expressions ([captures](params) { body }) Lambda expressions (lambda: expr) or small helper functions

In Java, how do you instantiate a non-static inner class Inner of Outer?

Does a nested class in C++ automatically hold a reference to its outer class instance?

Notes

Inner / Nested Classes :-

Nested Class ⇒ Class defined inside another class or function scope

Goal ⇒ Encapsulation ; logical grouping ; namespace clutter reduction

Static Nested Class :-

Java ⇒ static class Inner ; no outer instance binding

C++ / Python ⇒ Naturally independent by default ; access outer static members via Outer::var or Outer.var

Non-Static Inner Class :-

Java ⇒ Holds implicit outer reference (OuterClass.this) ; created via outerObj.new Inner()

C++ / Python ⇒ No auto-binding ; pass & store outer reference/pointer explicitly in constructor

Local & Anonymous Classes :-

Local Class ⇒ Defined inside function ; Java captures effectively final vars ; C++/Python require explicit constructor arguments

Anonymous / One-time ⇒ Java uses anonymous inner classes or lambdas ; C++ and Python prefer Lambdas

Primary source: Oracle Java Tutorials — Nested Classes & cppreference — Nested Class Declarations. Ask me anything that's unclear.

← Prev: The static Keyword Next: Class Relationships →

Questions? Ask your agent — you can follow up on any concept, quiz answer, or how this applies to a specific coding problem. Review the Java glossary or syntax quick reference for a compressed overview.