The difference between inner classes and static inner classes in Java

Inner class and static inner class


public class OuterClass {
    private int numPrivate = 1;
    public int numPublic = 2;
    public static int numPublicStatic = 3;
    private static int numPrivateStatic = 4;

    public void nonStaticPublicMethod(){
        System.out.println("using nonStaticPublicMethod");

    private void nonStaticPrivateMethod(){
        System.out.println("using nonStaticPrivateMethod");

    public static void staticPublicMethod(){
        System.out.println("using staticPublicMethod");

    private static void staticPrivateMethod(){
        System.out.println("using staticPrivateMethod");

    class InnerClass{

        //Inner class cannot have static declarations
        //static int numInnerClass = 4;
        //public static void test(){}

        int numNonStaticInnerClass = 5;

        public void print(){
            System.out.println("using InnerClass");
            System.out.println("access private field: "+numPrivate);
            System.out.println("access public field: "+numPublic);
            System.out.println("access public static field: "+numPublicStatic);
            System.out.println("access private static field: "+numPrivateStatic);
            System.out.println("access numNonStaticInnerClass: "+numNonStaticInnerClass);

    static class StaticNestedClass{

        static int numStaticNestedClass = 6;
        int numNonStaticNestedClass = 7;

        public void print(){
            System.out.println("using StaticNestedClass");
            System.out.println("access public static field: "+numPublicStatic);
            System.out.println("access private static field: "+numPrivateStatic);
            System.out.println("access numStaticNestedClass: "+numStaticNestedClass);
            System.out.println("access numNonStaticNestedClass: "+numNonStaticNestedClass);

    public static void main(String[] args) {
        //Inner class instance object
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = InnerClass();
        //Static inner class instantiation object
        OuterClass.StaticNestedClass nestedClass = new OuterClass.StaticNestedClass();


using InnerClass
access private field: 1
access public field: 2
access public static field: 3
access private static field: 4
access numNonStaticInnerClass: 5
using nonStaticPrivateMethod
using nonStaticPublicMethod
using staticPrivateMethod
using staticPublicMethod
using StaticNestedClass
access public static field: 3
access private static field: 4
access numStaticNestedClass: 6
access numNonStaticNestedClass: 7
using staticPrivateMethod
using staticPublicMethod

Static inner class usage

Accessing static inner classes through outer classes


Creating static inner class objects

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

How to use inner classes

External class must be instantiated before internal class can be instantiated

OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = InnerClass();

Difference between them

  1. Internal classes can be accessed even if they are private, both static and non-static

    • You can access all member variables and methods in a closed class (external class)
    • private member variables and methods in closed classes (external classes) can also be accessed
    • Static variables and static methods are not allowed in Inner Classes
  2. Static inner class

    • No access to non static variables or non static methods in closed classes (external classes)
    • static member variables and methods of private private in closed class (external class) can also be accessed
    • Static inner classes can have static variables and static methods
  3. Internal classes can be declared as private, public, protected, or package private. However, closed classes (external classes) can only be declared as public or package private

Exceptional case

public class ShadowTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {
            System.out.println("x = " + x);
            System.out.println("this.x = " + this.x);
            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);

    public static void main(String... args) {
        ShadowTest st = new ShadowTest();
        ShadowTest.FirstLevel fl = FirstLevel();

Output result

x = 23
this.x = 1
ShadowTest.this.x = 0


  1. Three variables x with the same name are defined in ShadowTest class

    • Member variable x of ShadowTest

    • Member variable x of FirstLevel inner class

    • Parameter x in methodInFirstLevel method

  2. The parameter x in the methodInFirstLevel method is under the shadow of the internal class FirstLevel, so when x is used in the methodInFirstLevel method, X points to the parameter X of the method, and the result of X is 23

  3. At this time, this points to the scope of the internal class FirstLevel, so the result of this.x is 1

  4. ShadowTest.this points to the scope of ShadowTest, and the result of ShadowTest.this.x is 1

Why use inner classes

  • This is a logical grouping of classes that are used only in one place: if one class is useful only for another, it is logical to embed it in the class and keep both together.
  • It adds encapsulation: consider two top-level classes a and B, where B needs to access the members of A. if the members of a are declared as private, B cannot access it. By hiding class B in class A, you can declare members of a private, and B can access them. In addition, B itself can be hidden from the outside world.
  • This can lead to code that is more readable and maintainable: nesting small classes within external classes brings the code closer to where it is used.


It is strongly recommended that you do not serialize internal classes, both local and anonymous.

If you serialize an internal class and then deserialize it using another JRE implementation, you may encounter compatibility issues.

Serialization of inner classes, including local and anonymous classes, is strongly discouraged. When the Java compiler compiles certain constructs, such as inner classes, it creates synthetic constructs; these are classes, methods, fields, and other constructs that do not have a corresponding construct in the source code. Synthetic constructs enable Java compilers to implement new Java language features without changes to the JVM. However, synthetic constructs can vary among different Java compiler implementations, which means that .class files can vary among different implementations as well. Consequently, you may have compatibility issues if you serialize an inner class and then deserialize it with a different JRE implementation. See the section Implicit and Synthetic Parameters in the section Obtaining Names of Method Parameters for more information about the synthetic constructs generated when an inner class is compiled.

Tags: Java jvm

Posted on Thu, 26 Mar 2020 10:22:03 -0400 by Weirdan