Skip to content
On this page

Inner Class

In Java programs, usually, we organize different classes under different packages. For classes under a package, they are at the same level and have no parent-child relationship:

java.lang
  ├── Math
  ├── Runnable
  ├── String
  └── ...

There is also a class that is defined inside another class, so it is called an inner class (Nested Class). There are several types of internal classes in Java, which are usually not used much, but you also need to understand how they are used.

If a class is defined inside another class, the class is an Inner Class:

java
class Outer {
  class Inner {
    // An Inner Class is defined
  }
}

Outer defined above is an ordinary class, and Inner is an Inner Class. The biggest difference between it and ordinary classes is that an instance of Inner Class cannot exist alone and must be attached to an instance of Outer Class. The sample code is as follows:

java
// inner class
public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer("Nested"); 
        Outer.Inner inner = outer.new Inner(); 
        inner.hello();
    }
}

class Outer {
    private String name;

    Outer(String name) {
        this.name = name;
    }

    class Inner {
        void hello() {
            System.out.println("Hello, " + Outer.this.name);
        }
    }
}

Observing the above code, to instantiate an Inner , we must first create an instance of Outer , and then call new of the Outer instance to create an Inner instance:

java
Outer.Inner inner = outer.new Inner();

This is because Inner Class, in addition to having a this pointing to itself, also implicitly holds an Outer Class instance, which can be accessed using Outer.this . Therefore, instantiating an Inner Class cannot be separated from the Outer instance.

Compared with ordinary Class, Inner Class has an additional "privilege" in addition to being able to reference Outer instances, that is, it can modify private fields of Outer Class. Because the scope of Inner Class is inside the Outer Class, it can access the Outer Class. private fields and methods.

Observing the .class file compiled by the Java compiler, we can find that the Outer class is compiled into Outer.class , and the Inner class is compiled into Outer$Inner.class .

Anonymous Class

There is also a way to define Inner Class, which does not need to explicitly define this Class in Outer Class, but is defined inside the method through an anonymous class (Anonymous Class). The sample code is as follows:

java
// Anonymous Class
public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer("Nested");
        outer.asyncHello();
    }
}

class Outer {
    private String name;

    Outer(String name) {
        this.name = name;
    }

    void asyncHello() {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello, " + Outer.this.name);
            }
        };
        new Thread(r).start();
    }
}

Observing asyncHello() method, we instantiate a Runnable inside the method. Runnable itself is an interface, and interfaces cannot be instantiated, so here we actually define an anonymous class that implements Runnable interface, instantiate the anonymous class through new , and then transform it into Runnable . When defining an anonymous class, you must instantiate it. The way to define an anonymous class is as follows:

java
Runnable r = new Runnable() {
    // Implement the necessary abstract methods...
};

Anonymous classes, like Inner Class, can access the private fields and methods of Outer Class. The reason why we need to define an anonymous class is because we usually don't care about the class name here, and we can write a lot less code than directly defining the Inner Class.

Observing the .class file compiled by the Java compiler, we can find that the Outer class is compiled into Outer.class , and the anonymous class is compiled into Outer$1.class . If there are multiple anonymous classes, the Java compiler will name each anonymous class as Outer$1 , Outer$2 , Outer$3 ...

In addition to interfaces, anonymous classes can also inherit from ordinary classes. Observe the following code:

java
// Anonymous Class
import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        HashMap<String, String> map1 = new HashMap<>();
        HashMap<String, String> map2 = new HashMap<>() {}; // anonymous class!
        HashMap<String, String> map3 = new HashMap<>() {
            {
                put("A", "1");
                put("B", "2");
            }
        };
        System.out.println(map3.get("A"));
    }
}

map1 is an ordinary HashMap instance, but map2 is an anonymous class instance, but the anonymous class inherits from HashMap . map3 is also an anonymous class instance inherited from HashMap , and static code block is added to initialize the data. Observing the compilation output, you can find two anonymous class files, Main$1.class and Main$2.class .

Static Nested Class

The last type of inner class is similar to Inner Class, but is modified with static , which is called static nested class:

java
// Static Nested Class
public class Main {
    public static void main(String[] args) {
        Outer.StaticNested sn = new Outer.StaticNested();
        sn.hello();
    }
}

class Outer {
    private static String NAME = "OUTER";

    private String name;

    Outer(String name) {
        this.name = name;
    }

    static class StaticNested {
        void hello() {
            System.out.println("Hello, " + Outer.NAME);
        }
    }
}

The inner class decorated with static is very different from the Inner Class. It is no longer attached to the instance of Outer , but a completely independent class. Therefore, it cannot refer to Outer.this , but it can access private static fields and static methods of Outer . If you move StaticNested outside of Outer , you will lose access to private .

Summary

Java's internal classes can be divided into three types: Inner Class, Anonymous Class and Static Nested Class;

Inner Class and Anonymous Class are essentially the same, and both must be attached to an instance of Outer Class, that is, they implicitly hold Outer.this instance and have private access rights to Outer Class;

Static Nested Class is an independent class, but has the private access rights of Outer Class.

Inner Class has loaded