Java Inner Class Tutorial: Types, Examples, and Rules

Java Inner Class Tutorial: Types, Examples, and Rules (2026)

Java Inner Class Tutorial: Types, Examples, and Rules

An inner class is a class defined inside another class. It sounds simple, but Java has four different kinds, and each one has its own rules. This guide walks through all four types with code, output, and the rules that interviewers ask about.

Nested Inner Class

  • A class defined inside a class is called an inner class.
// outer class or top-level class
class A {

    // inner class
    class B {

    }

}
  • Inner classes are used to organize a class's code.
class A {

    class Logic {
        // business logic here..
    }

    class View {
        // design here..
    }

}
  • An inner class can itself contain another class, called a nested inner class.
// outer class
class A {

    // inner class
    class B {

        // nested inner class
        class C {

        }

    }

}
  • Inner classes remove naming conflicts between classes.
class A {

    class B {
        class C {

        }
    }

    class D {
        class C {

        }
    }

}
  • Inner classes can be private, protected, default, public, static, final, abstract, and so on.
class A {

    private class B {

    }

    protected class C {

    }

    public class D {

    }

    final class E {

    }

    abstract class F {

    }

}
  • An inner class can access the private fields of the outer class.
class A {

    private int i = 10;

    class B {

        void show() {
            System.out.println(i);
        }

    }

    public static void main(String[] h) {
        // create outer class object
        A a = new A();

        // create inner class object through outer reference
        B b = a.new B();
        b.show();
    }
}

/* Note: Inner class B is non-static, so first we
need to create an instance of the outer class,
then use the outer reference to create an inner
class object. Otherwise there is a compile-time error. */

Output is : 10
  • A private field of one inner class can be accessed from another inner class inside the same outer class, through an object.
class A {

    class B {

        private int i = 10;

    }

    class C {

        void show() {
            System.out.println(new B().i);
        }

    }

    public static void main(String[] h) {

        A a = new A();
        C c = a.new C();
        c.show();

        // OR we can also call like below:

        new A().new C().show();
    }
}

Output is : 10
  • A class or interface can be an inner class, and an interface can also have an interface or class as an inner class.
class A {

    interface B {

    }

    class G {

    }

}

OR

interface C {

    class F {

    }

    interface D {

    }

}
  • A member interface can only be defined inside a top-level class or interface, or in a static inner class.
class A {

    interface T { // this is possible

    }

    class B {

        interface C { // compile-time error

        }
    }

    void show() {

        interface G { // compile-time error

        }
    }
}
  • The compiler creates a separate .class file for every inner class.
class A {

    class B {

    }

    static class C {

    }

    void show() {

        class F {

        }
    }
}

// When you compile, the compiler creates four .class files:
// A.class, A$B.class, A$C.class, and A$1F.class.

Types of inner class

There are 4 types of inner class:

  • Non-Static Inner class
  • Static Inner class
  • Local Inner class
  • Anonymous Inner class

1. Non-Static Inner class

  • A class defined inside a class without the static keyword is called a non-static inner class.
class A {

    // non-static inner class
    class B {

    }

}
  • A non-static inner class must be initialized through an outer reference to access its properties.
class A {

    void say() {
        System.out.println("Hey I am outer class method");
    }

    class B {
        void show() {
            System.out.println("Hey I am non-static inner class method");
        }
    }

    public static void main(String[] h) {
        A a = new A();
        a.say();

        B b = a.new B();
        b.show();
    }

}

Output is : Hey I am outer class method
Output is : Hey I am non-static inner class method
  • The this keyword and Outer.this remove naming conflicts between variables in nested inner classes.
class A {
    int i = 1;

    class B {
        int i = 2;

        class C {
            int i = 3;

            class D {
                int i = 4;

                void show() {
                    int i = 5;
                    System.out.println(i);        // 5
                    System.out.println(this.i);   // 4
                    System.out.println(C.this.i); // 3
                    System.out.println(B.this.i); // 2
                    System.out.println(A.this.i); // 1
                }

            }
        }
    }
}
  • A non-static inner class cannot have static members except constant variables (static final).
class A {

    class B {

        final static int i = 10; // only this is allowed

        static void show() {} // not allowed

        static int k = 100; // not allowed

    }

}

2. Static Inner class

  • A class defined inside a class with the static keyword is called a static inner class.
class A {

    // static inner class
    static class B {

    }
}
  • A static inner class can be accessed through the outer class name.
class A {

    static class B {

        static void show() {
            System.out.println("Hey I am static inner class");
        }

    }

    public static void main(String[] h) {
        A.B.show();
    }
}
  • A static inner class can also have non-static properties.
class A {

    static class B {

        int i = 100;

        void show() {
            System.out.println(i);
        }
    }

    public static void main(String[] h) {
        A.B a = new A.B();
        a.show();
    }
}

Output is : 100
  • A static inner class can also have its own main method.
class A {

    static class B {

        public static void main(String[] h) {
            System.out.println("Hello static inner class");
        }

    }

}

// compile by
javac A.java

// run by
java A$B

Output is : Hello static inner class

3. Local Inner class

  • A local inner class is defined inside a method, constructor, or block.
class A {

    void show() {

        // local inner class
        class B {

        }

    }
}
  • A local inner class cannot be declared private, static, protected, or public.
class A {

    void show() {

        // local inner class
        private class B { // compile-time error

        }

        protected class B { // compile-time error

        }

        public class B { // compile-time error

        }
    }
}
  • A local inner class can only be accessed within the method, constructor, or block body where it is defined.
class A {

    void show() {

        // local inner class
        class B {

            void goo() {
                System.out.println("Hey I am local inner class");
            }

        }
        B b = new B();
        b.goo();

    }

    public static void main(String[] h) {
        A a = new A();
        a.show();
    }
}

Output is : Hey I am local inner class

4. Anonymous Inner class

  • An anonymous inner class is a class that has no name.
  • It is a shorthand form of a local inner class.
  • It can create an object of an interface, an abstract class, or a normal class.
  • It is generated at runtime.
  • It can be passed as an argument to a method.
  • Its .class file is named OuterClass$1.class.

Example using a local inner class:

interface B {

    void add(int i, int j);

}

class A {

    void show(int i, int j) {

        class D implements B {

            public void add(int i, int j) {
                System.out.println(i + j);
            }
        }
        D d = new D();
        d.add(i, j);
    }

    public static void main(String[] h) {
        new A().show(2, 2);
    }
}

Output is : 4

Example using an anonymous inner class:

interface B {

    void add(int i, int j);

}

class A {

    public static void main(String[] h) {
        // this is the syntax of an anonymous inner class
        B b = new B() {

            public void add(int i, int j) {
                System.out.println(i + j);
            }

        };

        b.add(2, 2);

    }

}

// The anonymous class is generated at runtime when the object is created.
// The anonymous .class name is A$1.class

Output is : 4

Example using a lambda expression:

interface B {

    void add(int i, int j);

}

class A {

    public static void main(String[] h) {
        B b = (i, j) -> System.out.println(i + j);
        b.add(2, 2);

    }

}

Output is : 4

Summary

You now know the four types of inner classes, when each one runs, and the rules that break if you get them wrong. If you remember one thing, remember this: non-static inner classes need an outer object, static inner classes do not, local inner classes live inside a method, and anonymous inner classes have no name.

If you want to go deeper, try compiling a class with all four types and look at the generated .class files. The naming pattern (Outer$Inner.class, Outer$1.class) will make the compiler's behavior concrete.

No comments: