[Java Core Technology Volume] Deep understanding of Java's internal classes

Keywords: Java jvm Lambda

The analysis is illustrated:

This diagram shows the process of compiling and interpreting Java internal classes. You will see that the process is cumbersome.

For historical reasons, Java language specifications and byte code language specifications do not overlap, initially they overlap. But with the development of Java, something new needs to be added, such as generics, but the byte code language specifications cannot be easily changed because this involves compatibility issues. Only the compiler can move, compiling the Java source program through the compilerByte code files that meet the byte code language specifications are executed. Today's internal classes, like generics, were added later. The compiler actually did a lot of things later on about the implementation of internal classes. Although there is a tendency for internal classes to be replaced by Lambda expressions (Lambda expressions have their own interpreters), it still requires five more insights.

Direct introduction of condensation points:
1.Java source programs follow the Java language specifications, and the Java compiler compiles Java source programs according to the Java language specifications.
2. Byte code programs should follow the byte code language specification. The Java interpreter/JIT compiler of JVM interprets/compiles and runs the byte code program according to the byte code language specification.
3.Java language and byte code language are two different languages.Their language specifications have similarities and differences
For example:

  • In the same way: all have access controllers.Private members within a class can only be accessed by other members of the class, and private members of the class cannot be accessed by other classes.
  • Differences:
    1) Internal class is the specification of Java language, there is no internal class instruction in byte code specification, and JVM knows nothing about internal class.

2) Two methods with identical function signatures are not allowed in a class in the Java specification, regardless of the return type.In a class of byte code specifications, two methods with identical function signatures but different return types are allowed to be defined.

4.Java Compiler
For example, the Java language is like Chinese, the byte code language is like English, and the Java compiler is like a translation.This translation should not only translate Chinese that conforms to the Chinese language specification into English that conforms to the English language specification (this translation knows the difference between Chinese grammar and English grammar), but also translate English that has the same meaning as Chinese.
a) Compile Java source programs according to Java language specifications
b) The byte code program generated must meet the byte code language specification
c) The byte code program generated must strictly complete the functions and security of the Java source program

Since there is no internal class instruction in the byte code specification, the internal class is the specification for the Java language.Therefore, the Java compiler compiles the source program according to the Java syntax of the internal class, but also generates the byte code program according to the byte code syntax of the no internal class, and the byte code program generated without the internal class completes the function of the source program with the internal class.So the compiler is a free translation, not a literal one.
It is important to remember that the program you run is a byte code program, not a Java source program, and that the memory model is the result of the byte code run by the JVM virtual machine.Programmers must write high-quality, maintainable, extensible source programs that conform to the Java language specifications. Understanding byte codes and memory models can enhance programmers'understanding of Java compilers, Java interpreters, and especially Java source programs.That is, to better understand the running process, depth and details of the source program, to better complete the function and security of the source program.

In the Java language, an internal class is defined inside an external class.Internal classes can be static or decorated with public, default, protected, and private.(While external top-level classes can only use public and default, external top-level classes have no static state).In byte code languages, there is only the concept of classes, no concept of external and internal classes, and classes can only be accessed with public and default.

Note: Internal classes are a compiler phenomenon and the JVM virtual machine does not know how internal classes differ from regular classes.For an external class named Outer in the source file and an internal class named Inner defined internally, after compilation, Outer.class and Outer&dollar will appear; Inner.class two byte-code files and Outer and &dollar and Inner classes in the file. The compiler will translate the internal class into $ (dollar sign) separate the external class name from the internal class name.Virtual machines know nothing about this, and when they run, they also handle Outer$Inner as a regular class.So member variable/method names of internal classes can be the same as external classes.
Java internal class syntax describes the relationship between internal and external classes, regardless of the parent class of the external class (since the byte code program generated by the compiler must strictly complete the functions and security of the Java source program, to modify the external class, the parent of the external class may be a third-party class and cannot be modified).

Main reasons for using external classes:
1. Internal classes are generally used only for their external classes.
2. Internal class methods can access data in the external class where the internal class definition is located, including private data.The internal class provides some window into the external class.
3. Security) Access control: Internal classes can hide other classes in the same package.
4. Naming control: Although internal classes are renamed, their external classes are not renamed. Their compiled class name is a composite name.Therefore, internal class duplication and ambiguity can be avoided.
5. Anonymous internal classes can be used when defining an event listener and other callback functions.
6. It is also the most attractive reason that each internal class can inherit an interface independently, regardless of whether the external class has inherited an interface or not.Therefore, internal classes make multi-inherited solutions more complete.

Internal Class Identifier
Each class produces a.Class file whose name is the class name.Similarly, an internal class produces such a.Class file, but its name is not the class name of the internal class, but has strict restrictions: the name of the peripheral class, plus $, plus the name of the internal class.(decompile later, and you'll see that later)

There are six total internal classes:

Let's start by introducing member internal classes:
member inner class (non-static inner class)
Inside an external class, a non-static internal class is defined, called a member internal class.
According to the Java language syntax:

a) All instance members of the external class are visible to the internal class.Instance objects of internal classes of members, with references to instance objects of external classes, allow access to all members of external class instances, including private ones.
b) Static members of external classes are visible to internal classes.A member internal class can access all static members (including private) of an external class.
c) External classes are visible to internal classes.Instance objects of external classes can be generated new ly in internal classes.

d) Internal classes are visible to external classes.Because the compiled internal class is at least in the package and its constructor is at least in the package, instance objects of the internal class can be generated new ly in the external class.
External classes use internal classes in the usual way of class access. The only difference is that external classes can access all methods and properties of internal classes of members, including private methods and properties.
$Other Syntax Provisions$
e) Member internal classes can be accessed using public, protected, or private access modifiers, and internal classes can be hidden from other classes within the same package.Membership inner classes are typically set to private as member variables.
f) Member internal classes are non-static.Therefore, in member internal classes, static fields, static methods, and static internal classes cannot be defined because member internal classes need to create instance objects of external classes before they can create their own objects; however, non-static fields, non-static methods, and non-static internal classes can be defined.

An instance object of a Java internal class has an implicit reference to an instance object of an external class that created the internal class instance object.This pointer provides access to the full state (including private) of instance objects of external classes.

This combines the following examples:
Instance objects of member internal classes exist depending on instance objects of external classes, that is, if instance objects of member internal classes are to be created, an instance object of external classes must exist.Instance objects of internal classes cannot be created without instance objects of external classes. Instance objects of Cow external classes must be created before instance objects of CowLeg internal classes can be created.

Instance objects of the CowLeg class are created in methods of the Cow class.Since the CowLeg class is private, only Cow class methods can create instance objects of the CowLeg class.If the CowLeg class is public, code can be written inside and outside the Cow class: Cow cow = new Cow(); CowLeg cowLeg = cow.new CowLeg();

Local internal classes can access both their own data domains and all data domains of instance objects that create their external classes. weight can access private data domains of instance objects of external classes.

Special Java syntax rules for classes within members:
1) OuterClass.this
Syntax format of external class strength reference: OuterClass.this
For example, a private data field referencing an external class instance object in a method of an internal class instance object
System.out.println("The weight of the cow in which the legs are situated:"+ Cow.this.weight);
2) outerObject.new InnerClass(construction parameters)
Constructor syntax format for internal class instance objects:
outerObject.new InnerClass(construction parameters)
For example, create an external class instance object in a method of an external class instance object
CowLeg cl = this.new CowLeg(1.12,'black and white');
3) OuterClass.InnerClass
For example, if an internal class is visible outside the scope of an external class, it can be referenced as such.
Cow.CowLeg //If the CowLeg class is visible outside the Cow class

public class Cow {
    private double weight;

    // Two overloaded constructors for external classes
    public Cow() {
    }

    public Cow(double weight) {
        this.weight = weight;
    }

    // Define a member internal class
    private class CowLeg {
        // Two instance variables of a class within a member
        private double length;
        private String color;
        // Since instances of member internal classes depend on instances of external classes, member internal classes cannot contain static members
        //private static int age;


        // Two overloaded construction methods for classes within members
        public CowLeg() {
        }

        public CowLeg(double length, String color) {
            this.length = length;
            this.color = color;
        }

        // setter and getter methods for length, color
        public void setLength(double length) {
            this.length = length;
        }

        public double getLength() {
            return this.length;
        }

        public void setColor(String color) {
            this.color = color;
        }

        public String getColor() {
            return this.color;
        }

        // Method of member internal class
        public void info() {
            System.out.println("Current leg color is:" + color + ", High:" + length);
            // Direct access to private ly modified member variables of external classes
            //weight refers to the private data domain of the instance object of the external class that created the internal class instance object.
            System.out.println("The weight of the cow where the leg is located:" + weight);
            //If you don't write Cow.this., the compiler will add it automatically
            //System.out.println("The weight of the cow in which the legs are situated:"+ Cow.this.weight);
        }
    }

    public void test() {
        //Instance objects of the CowLeg class are created in the instance method of the Cow class.
        //Therefore, before you can create an instance object of a CowLeg internal class, you must first create an instance object of a Cow external class.
        CowLeg cl = new CowLeg(1.12, "Black and white");
        //If you do not write this. The compiler will automatically add it.
        //CowLeg cl = this.new CowLeg(1.12,'black and white');
        cl.info();
    }

    public static void main(String[] args) {
        Cow cow = new Cow(378.9);
        cow.test();
        //CowLeg cl = cow.new CowLeg(1.12,'black and white');
        //System.out.println("The color of this leg:"+cl.color);}
        //Translated to the following byte code, indicating that an external class can access private members of a class within a member.
        // System.out.println("The color of this leg:" + CowLeg.access0(cl)));
    }
}

Result:

Decompilation:


//Compiler compiled byte code class file:
1.    Cow.class
//
//The compiler adds the static method Cow.access Cow.access$0 (Cow arg0) (Cow arg0) to the external class.It returns the private domain weight of the object passed to it as a parameter.
//If the internal class does not access the private fields of the external class, the static method Cow.access Cow.access$0 (Cow arg0) (Cow arg0) will not be added to the external class.

public class Cow {
    private double weight;

    public Cow() {
    }

    public Cow(double weight) {
        this.weight = weight;
    }

    public void test() {
        //The compiler compiles CowLeg cl = new CowLeg(1.12, "black and white"); the statement is compiled as
        CowLeg cl = new CowLeg(this, 1.12D, "Black and white");
        cl.info();
    }

    //The compiler adds static methods to external classes
    static double access$0(Cow arg0){
        return arg0.weight;
    }

    public static void main(String[] args) {
        Cow cow = new Cow(378.9D);
        cow.test();
    }
}

2. Cow$CowLeg.class

//In order for the compiler to reference instance objects of external classes in instances of internal classes, an additional instance field, Cow this$0, must be added (this $0 name is synthesized by the compiler and should not be referenced in self-written code because the synthesized name may be different).
//In addition, the compiler modifies the constructors of all internal classes, adding a parameter Cow arg0 that references an instance of an external class.
//The constructor for an internal class is the same whether or not it accesses an external class, with a Cow arg0 parameter.

class Cow$CowLeg {
    private double length;
    private String color;
    //The compiler must add an additional instance field, Cow this$0
    final Cow this$0;

    //The compiler must add a parameter Cow arg0 that references an instance of an external class in the construction method of an internal class
    public Cow$CowLeg(Cow arg0) {
        this.this$0 = arg0;
    }

    public Cow$CowLeg(Cow arg0, double length, String color) {
        this.this$0 = arg0;
        this.length = length;
        this.color = color;
    }

    public void setLength(double length) {
        this.length = length;
    }

    public double getLength() {
        return this.length;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getColor() {
        return this.color;
    }

    public void info() {
        System.out.println("Current leg color is:" + this.color + ", High:" + this.length);
        System.out.println("The weight of the cow where the leg is located:" + Cow.access$0(this.this$0));
    }
}

Is it clear all at once!
Take a look at its memory object model

Note: Why member internal classes cannot define static properties or static methods

//According to the definition of class within a member:
//1. First generate instance objects of external classes
//2. Then generate member internal class instance objects bound to external class instance objects
//External class instance object generation must precede generation of internal class instance objects within members

public class InnerClassDemo {
    //For final modifier member variables, it means that the variable is read-only and can only be assigned once. There are only two possible assignments where we have to give them initial values.
    //1) Assignment when declaring the member variable:
    //    a) If the value of an expression is a constant expression (returning basic type data), the compiler calculates the value of the expression at compile time and knows the value.Then the compiler may optimize the program at compile time.
    //    b) If it is not a constant expression (returning reference type data), the compiler will compile without knowing the value.
    //2) Assignment in a construction method or at runtime will not be known by the compiler at compile time.

    //Instance member variable is initialized to 0 by default
    int x;

    //Static member variables must be explicitly initialized, either by assignment at declaration time or in a static block.Otherwise, the grammar is wrong.
    static final int i;
    static final int j = 2;
    //Static block, static code execution for a static block when the class is loaded into memory by the JVM.
    static{
        i = 1;
        System.out.println("i = " + i);
        System.out.println("j = " + j);
    }

    public static void main(String[] args) {

        System.out.println("welcom!");
    }


class InnerClass{

        //1. In member internal classes, only the compiler assigns a constant expression to the right of the assignment sign at compile time (the basic type value of the expression can be calculated at compile time).
        //   Static read-only constants can only exist if read-only static constants are on the left
        //   The compiler then uses him as a compile-time constant, which is essentially irrelevant to an instance of this external class.
        //static final int i = 50;  
        //static final String str =  "s"; 

        //2. Neither of the following is allowed:
        //2.1 is also a static final read-only static variable, but it is assigned at run time in the construction method and is not known at compile time.
        //static final int i;  
        //static final String str;  
        //2.2 Although it is also a static final read-only static variable, the right side of the assignment number is not a constant expression (returning reference type data), and the instance value it references is compiled without knowing it.
        //static final String str = new String(""); 
        //2.3 is a static variable that can be dynamically assigned at runtime
        //static  int i = 50;  

        //3. But there is no external class instance This internal class initializes variables without an external class instance, which is contrary to the definition of member internal classes.
        //   Since 3 is not possible, 2 is not.Because the compiler cannot distinguish between 2 and 3.  
        //static InnerClass innerClass = new InnerClass(); 

        //4. In static methods, but no external class instances  
        //static void method() { InnerClass innerClass = new  InnerClass(); };
    }
}  

In fact, the internal class is not entirely static-like modification, as long as it meets the first case is possible.
The compiler cannot distinguish the second from the third, which is certainly not compatible with the definition of internal member classes, so the second is also syntactically prohibited.
Third, according to the initialization process, we know that the static variable must be explicitly initialized when the class is loaded, so the instance object of our InnerClass member's internal class is generated when there is no instance object of the InnerClassDemo external class.In this way, the internal class of a member is out of the control of the external class, and objects of the internal class can be generated without objects of the external class, which is contrary to the definition of the internal class of a member, because we know that objects of the internal class of a member must be objects of the external class before they can be created, and objects of the internal class of a member that are separate from its external class will not exist and are bound.Together, member internal classes cannot define static variables.

Here's the second
static inner class / Static Nested Class
Restrict further the use of member internal classes by statically hiding one class inside another if the instance object of the internal class does not need to reference the instance object of the external class.
Inside an external class, a static internal class is defined, called a static internal class.(or nested class)
Tip: Static internal classes are not used much in practice.
According to the Java language syntax:

a) Static members of external classes are visible to internal classes.Static internal classes have access to all static members (including private) of external classes.
b) External classes are visible to internal classes.Instance objects of external classes can be generated new ly in internal classes.
c) Instance members of external classes are not visible to internal classes.Instance objects of static internal classes have no reference to instance objects of external classes, so external class instances cannot be accessed.

d) Internal classes are visible to external classes.Because the compiled internal class is at least in the package and its constructor is at least in the package, instance objects of the internal class can be generated new ly in the external class.
Other grammars:
e) Static internal classes can be accessed using public, protected, or private access modifiers, and internal classes can be hidden from other classes within the same package.Typically set as a member variable to private.
f) Static internal classes are static.So in a static internal class, you can define static fields, static methods, and static internal classes; you can also define non-static fields, non-static methods, and non-static internal classes.

Static internal classes do not have instance fields and constructor parameters added automatically by the compiler compared to member internal classes.That is, instances of static internal classes cannot access instance members of external classes.
Static internal classes are not used much in practice.For example, during program testing, to avoid writing the code for the main method in each Java source file, you can write the main method to a static internal class to reduce the amount of code written and make the code simpler.

public class StaticInnerClassDemo {
    private int prop1 = 5;
    private static int prop2 = 9;

    static class StaticInnerClass {
        // Static internal classes can contain static members
        // private static int age;
        // private int number = 28;

        public void accessOuterProp() {
            // An error occurred in the following code:
            // Static internal classes cannot directly access instance variables of external classes
            //System.out.println(prop1);
            // The following code is OK
            System.out.println(prop2);
        }
    }

    public static void main(String[] args) {
        StaticInnerClass staticInnerClass = new StaticInnerClass();
        staticInnerClass.accessOuterProp();
        //System.out.println(staticInnerClass.age);
//Translated to the following byte code, indicating that external classes can access private members of static internal classes.
//System.out.println(StaticInnerClass.access$100(staticInnerClass));
    }
}

Compiler compiled byte code class file:
1. StaticInnerClassDemo.class

//The compiler adds the static method StaticInnerClassDemo.access$0() to the external class, which returns the private static domain prop2.Access private static fields through static methods.
//If the internal class does not access static private members of the external class, the static method StaticInnerClassDemo. access StaticInnerClassDemo. access $0 () () will not be added.

public class StaticInnerClassDemo {
    private int prop1 = 5;
    private static int prop2 = 9;

    static int access$0(){
        return StaticInnerClassDemo.prop2;
    }

    public static void main(String[] args) {
        StaticInnerClass staticInnerClass = new StaticInnerClass();
        staticInnerClass.accessOuterProp();
    }
}

2. StaticInnerClassDemo$StaticInnerClass.class

class StaticInnerClassDemo$StaticInnerClass {

    public void accessOuterProp() {
        System.out.println(StaticInnerClassDemo.access$0());
    }
}

Memory object model for static classes:

Appendix: Differences between java internal classes and static internal classes
1. Static internal classes can have static members (methods, properties), while non-static internal classes cannot have static members (methods, properties).
2. Static internal classes can only access static members of external classes, while non-static internal classes can access all members (methods, properties) of external classes.
3. Method for instantiating a non-static internal class:

  • a. Generate an instance of an external class object
    OutClassTest oc1 = new OutClassTest();
  • b. Generate internal class objects from object instances of external classes
    OutClassTest.InnerClass no_static_inner = oc1.new InnerClass();

4. Method for instantiating a static internal class:

  • a. Instantiate internal class objects directly, independent of instances of external classes

           OutClassTest.InnerStaticClass inner = 
  1. OutClassTest.InnerStaticClass();
  • b. Call a method or static variable of an internal static class, called directly by the class name

           OutClassTest.InnerStaticClass.static_value
      OutClassTest.InnerStaticClass.getMessage()

Then another internal class is introduced:
local inner class
In methods of external classes, a nonstatic named internal class is defined, called a local internal class.(This name is given because the internal class can access the parameters and local variables of the external class method)
They can be divided into local internal classes inside instance methods of external classes and local internal classes inside static methods of external classes.
Tip: Local internal classes are rarely used in actual development, only because they have a small scope and can only be used in current methods.

According to the Java language syntax:
1. Local internal classes inside instance methods of external classes.

a) The parameter of the instance method is visible to the local internal class.Instance objects of local internal classes can have fields for the formal parameters of instance methods of external classes and access the formal parameters of instance methods of external classes.These parameters must be declared final before JDK8, but they are not required in JDK8.
b) The local variables of the instance method are visible to the local internal classes.Instance objects of local internal classes can have fields of local variables of instance methods of external classes and access local variables of instance methods of external classes.These local variables must be declared final before JDK8, but they are not required in JDK8.

a) Instance members of external classes are visible to local internal classes.Instance objects of local internal classes have references to instance objects of external classes, so all members of external class instances, including private ones, can be accessed.
b) Static members of external classes are visible to local internal classes.Local internal classes have access to all static members (including private) of external classes.
c) External classes are visible to local internal classes.Instance objects of external classes can be generated new ly in internal classes.

d) Instance methods of local internal classes are visible to external classes.Because the compiled internal class is at least in the package and its constructor is at least in the package, instance objects of local internal classes can be generated new ly in the instance methods of external classes.

e) Local internal classes cannot be accessed using public, protected, or private access modifiers, and their scope is limited to the method block in which the local internal class is declared, so instance objects of local internal classes cannot be generated new ly in methods of external classes.No method knows the existence of an internal class except the external class method where the local internal class is located.
Other grammatical provisions:
f) Local internal classes are nonstatic.Therefore, in a local internal class, you cannot define static fields, static methods, and static internal classes; however, you can define non-static fields, non-static methods, and non-static internal classes.

class InstanceLocalOut {
    private int age = 12;

    // 
//Final parameters, final local variables, are the syntax of the compiler and do not exist in the byte code.
//Use final to make the formal parameters, local variables, and field copies created by local internal class instances consistent.
//1. In versions prior to JDK8, final modifiers must be written
//   1) If a final parameter is written, the compiler is informed that the parameter cannot be changed within the method;
//   2) If a final local variable is written, the compiler is informed that the local variable can only be assigned once within the method.
//   That cannot be changed in the future;
//2. In JDK8 and later versions, there is no need to write the final modifier (or write it on) anymore, which is automatically determined by the compiler
//   1) If a parameter is used in a local internal class,
//      The compiler automatically determines at compile time that the parameters cannot be changed within the method.
//   2) If the local internal class uses local variables within the method,
//      Then the compiler automatically determines at compile time that a local variable can only be assigned once inside a method and cannot be changed later.
    public void Print(final int x) {
        final int m = 8;

// Define a local internal class in the instance method
        class InstanceLocalIn {
            // Instance methods for local internal classes
            public void inPrint() {
                // Direct access to private ly modified member variable age of an external class
                System.out.println(age);
                // Parameter x that directly accesses an external class instance method
                System.out.println(x);
                // Direct access to local variable m of external class instance method
                System.out.println(m);
            }
        }

// InstanceLocalIn class instance object is created in InstanceLocalOut class instance method.
//Therefore, before you can create an instance object of an InstanceLocalIn local internal class, you must first create an instance object of an InstanceLocalOut external class (this is the hidden parameter of the Print method of the external class).            
        InstanceLocalIn instanceLocalIn = new InstanceLocalIn();
        instanceLocalIn.inPrint();
    }
}

public class InstanceLocalInnerClass {
    public static void main(String[] args) {
        InstanceLocalOut out = new InstanceLocalOut();
        out.Print(3);
    }
}

Decompilation:

//External Class
//The compiler added the static method InstanceLocalOut.access InstanceLocalOut.access$0 (InstanceLocalOut arg0) (InstanceLocalOut arg0) to the external class.It returns the private domain age of the object passed to it as a parameter.
//If the internal class does not access the private fields of the external class, the static method InstanceLocalOut.access InstanceLocalOut.access$0 (InstanceLocalOut arg0) (InstanceLocalOut arg0) will not be added to the external class.
--------------------------------------------------------------------
import InstanceLocalOut.1InstanceLocalIn;

class InstanceLocalOut {
    private int age = 12;

    public void Print(int x) {
        byte m = 8;
//The compiler compiles the InstanceLocalIn instanceLocalIn = new InstanceLocalIn(); statement as
        1InstanceLocalIn instanceLocalIn = new 1InstanceLocalIn(this, x, m);
        instanceLocalIn.inPrint();
    }

    //The compiler adds static methods to external classes
    static double access$0(InstanceLocalOut arg0){
        return arg0.age;
    }

}

//Local internal class in instance method of external class
//In order for the compiler to reference instance objects of external classes in instances of internal classes, it must add an additional instance domain, InstanceLocalOut this InstanceLocalOut this $0 (this $0 (this InstanceLocalOut this $0 (this $0  name is synthesized by the compiler and should not be referenced in self-written code).
//If an internal class accesses parameter x in an instance method of an external class, the compiler modifies the internal class and adds an additional instance domain parameter, int val$x.Otherwise, additional instance domains will not be added.
//If an internal class accesses a local variable m in an instance method of an external class, the compiler modifies the internal class and adds an additional instance domain parameter, int val$m.Otherwise, additional instance domains will not be added.

class InstanceLocalOut$1InstanceLocalIn {
    final InstanceLocalOut this$0;
    private final int val$x;
    private final int val$m;

    InstanceLocalOut$1InstanceLocalIn(InstanceLocalOut arg0, int arg1, int arg2) {
        this.this$0 = arg0;
        this.val$x = arg1;
        this.val$m = arg2;
    }

    public void inPrint() {
        System.out.println(InstanceLocalOut.access$0(this.this$0));
        System.out.println(this.val$x);
        System.out.println(this.val$m);
    }
}

Memory execution model for external classes:

Local internal classes in static methods of external classes
A local internal class in a static method is the same as a local internal class in an instance method except that it cannot access an instance of the external class (because it does not have a reference to an instance object of the external class).

According to the Java language syntax:


a) Static members of external classes are visible to local internal classes.Local internal classes have access to all static members (including private) of external classes.
b) External classes are visible to local internal classes.Instance objects of external classes can be generated new ly in local internal classes.
c) Instance members of external classes are not visible to internal classes.Instance objects of local internal classes have no reference to instance objects of external classes, so all members of external class instances cannot be accessed.

d) Static methods of local internal classes are visible to external classes.Because the compiled internal class is at least in the package and its constructor is at least in the package, instance objects of the internal class can be generated new ly in static methods of the external class.

e) Local internal classes cannot be accessed using public, protected, or private access modifiers, and their scope is limited to the method block in which the local internal class is declared.
Other grammatical provisions:
f) Local internal classes are nonstatic.Therefore, in a local internal class, you cannot define static fields, static methods, and static internal classes; however, you can define non-static fields, non-static methods, and non-static internal classes.

class StaticLocalOut {
    private int age = 12;

    static public void print(int x) {
            final int m = 8;
        class StaticLocalIn {
            public void inPrint() {
               //Local internal classes in static methods cannot access instances of external classes
               //System.out.println(age);
               System.out.println(x);
               System.out.println(m);
            }
        }
        StaticLocalIn staticLocalIn = new StaticLocalIn();
        staticLocalIn.inPrint();
    }
}

public class StaticLocalInnerClass {
    public static void main(String[] args) {
        StaticLocalOut.Print(3);
    }
}

Compiler compiled byte code class file:

//External Class
import StaticLocalOut.1StaticLocalIn;

class StaticLocalOut {
    private int age = 12;

    public static void print(int x) {
      byte m = 8;
      1StaticLocalIn staticLocalIn = new 1StaticLocalIn(x, m);
      staticLocalIn.inPrint();
   }
}
//Local internal classes in static methods of external classes
class StaticLocalOut$1StaticLocalIn {
    StaticLocalOut$1StaticLocalIn(int arg0, int arg1) {
        this.val$x = arg0;
        this.val$m = arg1;
    }

    public void inPrint() {
        System.out.println(this.val$x);
        System.out.println(this.val$m);
    }
}

Memory model for local internal classes within static methods of external classes

anonymous inner class
Take the use of local internal classes one step further, and if you only create one object of this class, you do not have to name it.In terms of usage, the difference between an anonymous inner class and a local inner class is that one is anonymous, the other is named, and the others are the same.(Anonymous means that the compiler automatically gives an internal name to the internal class)
In methods of external classes, a non-static internal class without a class name is defined, called an anonymous internal class.
Anonymous internal classes are suitable for classes that only need to be used once. When an anonymous internal class is created, an instance object of the class is created immediately. Anonymous classes cannot be reused.
It can be divided into: anonymous internal classes inside instance methods of external classes,
An anonymous internal class inside a static method of an external class.

Tip: It is best to use lambda expressions instead of anonymous internal classes.

According to the Java language syntax:
1. Anonymous internal class inside instance methods of external classes.

a) The parameter of the instance method is visible to the anonymous inner class.An instance object of an anonymous internal class can have fields for the parameter of an instance method of an external class and access the parameter of an instance method of an external class.These parameters must be declared final before JDK8, but they are not required in JDK8.
b) Local variables of the instance method are visible to anonymous internal classes.Instance objects of anonymous internal classes can have fields for local variables of instance methods of external classes and access local variables of instance methods of external classes.These local variables must be declared final before JDK8, but they are not required in JDK8.

c) Instance members of external classes are visible to anonymous internal classes.Instance objects of anonymous internal classes, with references to instance objects of external classes, can access all members of external class instances, including private ones.
d) Static members of external classes are visible to anonymous internal classes.Anonymous internal classes have access to all static members (including private) of external classes.
e) External classes are visible to local internal classes.Instance objects of external classes can be generated new ly in anonymous internal classes.

f) Anonymous internal class is visible to external class this instance method.Since the compiled internal class is at least in the package and its constructor is at least in the package, the instance method in the external class can new generate an instance object of the internal class.

g) Anonymous internal classes cannot be accessed using public, protected, or private access modifiers, and their scope is limited to the method block in which the anonymous internal class is declared.
Other grammatical provisions:
h) Since the name of the constructor must be the same as the class name, and anonymous classes have no class name, anonymous internal classes cannot have constructors.Instead, constructor parameters are passed to the parent constructor.
i) Anonymous internal classes are non-static.Therefore, in an anonymous internal class, you cannot define static fields, static methods, and static internal classes; however, you can define non-static fields, non-static methods, and non-static internal classes.

class FatherofAnonIn {
    protected int a;
    FatherofAnonIn(int a){
        this.a = a;
    }
}

class InstanceAnonOut {
    private int age = 12;

    public void Print(int x) {
        int m = 8;

//1. Create a derived anonymous class of the FatherofAnonIn class
//2. Anonymous internal classes cannot have a defined instance constructor, pass instance constructor parameters to the parent class instance constructor for initialization.
//3. Generate instance objects of anonymous internal classes
//4. Call methods of anonymous classes through instance objects of anonymous internal classes
        (new FatherofAnonIn(10){
            public void inPrint() {
                System.out.println(age);
                System.out.println(x);
                System.out.println(m);
                System.out.println(a);
            }
        }).inPrint();
    }
}

public class InstanceAnonInnerClass {
    public static void main(String[] args) {
        InstanceAnonOut out = new InstanceAnonOut();
        out.Print(3);
    }
}

Compiled byte code:


//External Class
import InstanceAnonOut.1;

class InstanceAnonOut {
    private int age = 12;

    public void Print(int x) {
      byte m = 8;
      (new 1(this, 10, x, m)).inPrint();
   }

//The compiler adds static methods to external classes
static int access$0(InstanceAnonOut arg0){
        return arg0.age;
}

}

//Anonymous Inner Class
class InstanceAnonOut$1 extends FatherofAnonIn {
    InstanceAnonOut$1(InstanceAnonOut arg0, int $anonymous0, int arg2, int arg3) {
        super($anonymous0);
        this.this$0 = arg0;
        this.val$x = arg2;
        this.val$m = arg3;
    }

    public void inPrint() {
        System.out.println(InstanceAnonOut.access$0(this.this$0));
        System.out.println(this.val$x);
        System.out.println(this.val$m);
        System.out.println(this.a);
    }
}

Memory model for anonymous internal classes inside instance methods of external classes

Anonymous inner class in static methods of external classes
Anonymous internal classes in static methods are the same as anonymous internal classes in instance methods except that they cannot access instances of external classes (because they do not have references to instance objects of external classes).

a) Parameters of static methods are visible to anonymous internal classes.Instance objects of anonymous internal classes can have fields for the parameters of static methods of external classes and access the parameters of static methods of external classes.These parameters must be declared final before JDK8, but they are not required in JDK8.
b) Local variables of static methods are visible to anonymous internal classes.Instance objects of anonymous internal classes can have fields for local variables of static methods of external classes and access local variables of static methods of external classes.These local variables must be declared final before JDK8, but they are not required in JDK8.

c) Static members of external classes are visible to anonymous internal classes.Anonymous internal classes have access to all static members (including private) of external classes.
d) External classes are visible to anonymous local internal classes.Instance objects of external classes can be generated new ly in local internal classes.
e) Instance members of external classes are not visible to anonymous internal classes.An instance object of an anonymous internal class has no reference to an instance object of an external class, so all members of the external class instance, including private, cannot be accessed.


f) Static methods of internal classes are visible to external classes.Because the compiled internal class is at least in the package and its constructor is at least in the package, instance objects of the internal class can be generated new ly in static methods of the external class.

g) Anonymous internal classes cannot be accessed using public, protected, or private access modifiers, and their scope is limited to the method block in which the anonymous internal class is declared.

Other grammatical provisions:
h) Anonymous internal classes cannot have constructors.The constructor cannot be written because the anonymous class has no class name.Instead, constructor parameters are passed to the superclass constructor.
i) Anonymous internal classes are non-static.Therefore, in an anonymous internal class, you cannot define static fields, static methods, and static internal classes; however, you can define non-static fields, non-static methods, and non-static internal classes.

//Source program:
class FatherofAnonIn {
    protected int a;
    FatherofAnonIn(int a){
        this.a = a;
    }
}

class StaticAnonOut {
    private int age = 12;

    public static void print(int x) {
        int m = 8;
        
        (new FatherofAnonIn(10){
            public void inPrint() {
               //System.out.println(age);
               System.out.println(x);
               System.out.println(m);
               System.out.println(a);
            }
        }).inPrint();
     }
}

public class StaticAnonInnerClass {
    public static void main(String[] args) {
        StaticAnonOut.Print(3);
    }
}

Compiled byte code:

//External Class
import StaticAnonOut.1;

class StaticAnonOut {
    private int age = 12;

    public static void print(int x) {
      byte m = 8;
      (new 1(10, x, m)).inPrint();
   }
}

//Anonymous Inner Class
class StaticAnonOut$1 extends FatherofAnonIn {
    StaticAnonOut$1(int $anonymous0, int arg1, int arg2) {
        super($anonymous0);
        this.val$x = arg1;
        this.val$m = arg2;
    }

    public void inPrint() {
        System.out.println(this.val$x);
        System.out.println(this.val$m);
        System.out.println(this.a);
    }
}

Memory model for anonymous internal classes inside static methods of external classes

Posted by renegade44 on Tue, 12 Nov 2019 18:55:27 -0800