In-depth analysis of Java class construction methods

Source: Internet
Author: User
Summary: This article displays the running output of a well-constructed class structure and the actually generated Java bytecode (bytecode) using the javap tool) shows Java programmers how a class is constructed and generated at runtime.

Keywords: Java construct javap bytecode

According to Java specifications, the construction process of a class instance follows the following sequence:
1. If the constructor is a constructor or constructor, bind the constructor to the constructor.
2. in memory allocation, non-static members are assigned an initial value (the value of members of the original type is a specified value, for example, int type is 0, float type is 0.0f, and boolean type is false; the initial value of the object type is null). Static members belong to class objects rather than class instances. Therefore, the generation of class instances is not constructed or initialized by static members, the generation time of static members will be described later.
3. if this () call exists in the constructor (it can be another this () call with parameters), execute it. After the execution is complete, proceed to step 1, if this is not called, proceed to the next step.
4. execute an explicit super () call (which can be another super () call with parameters) or an implicit super () call (default constructor ), this step further enters the construction process of the parent class and continues to push to the construction of the object.
5. assign values and initialize blocks to Members in the execution class declaration.
6. Execute other statements in the constructor.

Now let's take a look at a well-constructed instance:

ClassParent
{
IntPM1;
IntPM2 = 10;
IntPM3 = pmethod ();
{
System. Out. println ("Parent's instance initialize block ");
}
Public Static IntSpm1 = 10;
Static
{
System. Out. println ("Parent's static initialize block ");
}

Parent ()
{
System. Out. println ("Parent's default constructor ");
}
Static Void StaticMethod ()
{
System. Out. println ("Parent's staticmethod ");
}

IntPmethod ()
{
System. Out. println ("Parent's method ");
Return3;
}
}

ClassChildExtendsParent
{
IntCm1;
IntCm2 = 10;
IntCm3 = cmethod ();
Other CO;
Public Static IntScm1 = 10;
{
System. Out. println ("Child's instance initialize block ");
}
Static
{
System. Out. println ("Child's static initialize block ");
}

Child ()
{
CO =NewOther ();
System. Out. println ("Child's default constructor ");
}
Child (IntM)
{
This();
Cm1 = m;
System. Out. println ("child's self-define constructor ");
}
Static Void StaticMethod ()
{
System. Out. println ("Child's staticmethod ");
}

IntCmethod ()
{
System. Out. println ("Child's method ");
Return3;
}

}

ClassOther
{
IntOm1;
Other (){
System. Out. println ("other's default constructor ");
}

}

Public ClassInitializationtest
{
Public Static VoidMain (string ARGs [])
{
Child C;
System. Out. println ("program start ");
System. Out. println (child. scm1 );
C =NewChild (10 );
System. Out. println ("program end ");
}
}

Enter the directory where the file is located, and then
Compile this file: javac initializationtest. Java
Run this program: Java? Classpath. initializationtest
The result is:
Program start
Parent's static initialize Block
Child's static initialize Block
10
Parent's Method
Parent's instance initialize Block
Parent's default constructor
Child's Method
Child's instance initialize Block
Other's default constructor
Child's default constructor
Child's self-define Constructor
Program end

If you have not read the preceding description about the class construction, it is easy to misunderstand that the class construction sequence is as follows (ignore parameter binding, memory allocation, and non-static member default value assignment ):
1. initialize and assign values to non-static members of the parent class and execute the initialization block (the order of this is determined by the writing order in the source file. You can place the initialization block before the member declaration, the initialization block will be executed first, and the above Code can be verified after a slight change .)
2. Call the constructor of the parent class to construct the parent class.
3. Complete non-static member initialization assignment and execute initialization blocks.
4. Call the constructor to construct the object and execute other content in the constructor.

If the program output results can be reasonably interpreted based on the order given in the preceding Java specification, how can we see the order in the Specification rather than the order inferred from the program output?
Next we will use the JDK's built-in javap tool to look at the actual sequence. This tool is a tool for generating a file in the mnemonic format based on the compiled bytecode, just like generating assembly code based on machine code.
Decompilation: javap-C-classpath. Child
The output result is (marked, and each part to be explained is displayed in bold and italic ):
Compiled from initializationtest. Java
Class Child extends parent {
Int cm1;
Int cm2;
Int cm3;
Other CO;
Public static int scm1;
Static {};
Child ();
Child (INT );
Int cmethod ();
Static void staticmethod ();
}

Method static {}
0 bipush 10
2 putstatic #22 <field int scm1>
5 getstatic #20 <field java. Io. printstream out>
8 LDC #5 <string "Child's static initialize block">
10 invokevirtual #21 <method void println (Java. Lang. String)>
13 return

Method child ()
0 aload_0
1 invokespecial #14 <method parent ()>
4 aload_0
5 bipush 10
7 putfield #16 <field int cm2>
10 aload_0
11 aload_0
12 invokevirtual #18 <method int cmethod ()>
15 putfield #17 <field int cm3>
18 getstatic #20 <field java. Io. printstream out>
21 LDC #2 <string "Child's instance initialize block">
23 invokevirtual #21 <method void println (Java. Lang. String)>
26 aload_0
27 new #8 <class other>
30 DUP
31 invokespecial #13 <method other ()>
34 putfield #19 <field other Co>
37 getstatic #20 <field java. Io. printstream out>
40 LDC #1 <string "Child's default constructor">
42 invokevirtual #21 <method void println (Java. Lang. String)>
45 return

Method child (INT)
0 aload_0
1 invokespecial #12 <method child ()>
4 aload_0
5 iload_1
6 putfield #15 <field int cm1>
9 getstatic #20 <field java. Io. printstream out>
12 LDC #4 <string "child's self-define constructor">
14 invokevirtual #21 <method void println (Java. Lang. String)>
17 return

Method int cmethod ()
0 getstatic #20 <field java. Io. printstream out>
3 LDC #3 <string "Child's method">
5 invokevirtual #21 <method void println (Java. Lang. String)>
8 iconst_3
9 ireturn

Method void staticmethod ()
0 getstatic #20 <field java. Io. printstream out>
3 LDC #6 <string "Child's staticmethod">
5 invokevirtual #21 <method void println (Java. Lang. String)>
8 return

Please carefully view the output and compare it with the source code.
The following explains how to obtain the actual construction sequence of the class instance based on the output. Before starting the description, explain the format of the output statement. the first digit in the statement is the Offset Value of the command, this can be ignored here. The second item is the instruction mnemonic, which can be literally understood as the meaning of the instruction, for example, the getstatic command pushes a static member into a data structure called the operand stack (Subsequent commands can reference the Members in this data structure), while the invokevirtual command calls the Java Virtual Machine Method, the third item is the operand (# followed by a number, which is actually a member mark of the class). Some commands do not have this item, some commands, like some commands in assembly commands, do not require an operand (which may be implicit or not required at all). This is a special feature of Java, if you check the bytecode directly, you will see that the member information is not directly embedded with instructions, but is stored in a shared pool as all constants used by Java classes, storing member information in a constant pool can reduce the size of bytecode commands, because commands only need to store an index in the constant pool instead of an integer. Constants. It must be noted that the project sequence in the constant pool is related to the compiler. Therefore, the output in your environment may be different from the one given above, the fourth item is the description of the previous operations, and there is no actual bytecode. Based on this, you can clearly find out which member is actually used or which method is called, this is also the convenience that javap provides for us. Now you can easily understand the above results and the content to be described below. For more information about the Java bytecode, find the relevant information.
Let's take a look at the first part, which is like a standard C ++ class declaration. After the member declaration, there are no member initialization assignment statements and initialization blocks. When will these statements be executed? Don't worry. Continue.
The second block is a method static {}. Let's take a look at the first part. It is processed as a static method (as can be seen from the previous method). This is the static initialization block in the source code, the following statement shows that it executes system. out. println ("Child's static initialize block") statement, because this method does not have a method name, it cannot be explicitly called, and where it is called will be described later.
The third part is the implementation of the default constructor. This is the focus of this article. Because the default constructor in the source code does not explicitly call this method, there is no this call (compare the first two sentences of the Construction Method with parameters in the next section ), there is no explicit super call, so the default constructor of the parent class is called implicitly, that is, the first two statements (mainly statements invokespecial #14 <method parent ()> ), it calls the constructor of the parent class, which is similar to the constructor of this class (you can use javap? C? Classpath. parent decompile the bytecode of the parent class to see the construction process of this class); followed by the execution of the first initialization value assignment statement in the source code cm2 = 10 (that is, the next three statements, mainly bipush 10 and putfield #15 <field int cm2>. Here, we answer the question in the first block, that is, where is the initialization value assignment statement .); Next, execute cm3 = cmethod () (The following four statements), and then execute the Content System in the initialization block. out. println ("Child's instance initialize block, CO = new other () (the next five statements) and system. out. println ("Child's default constructor") (the next three statements), return after the last method is executed (the last statement is return ).
I don't believe you need to explain the remaining parts. If you have a constructor, call the constructor without parameters and execute your own method body. The member method cmethod executes a print statement and returns a constant 3, the static method staticmethod executes a print statement.
In addition, you can remove this call from the constructor with parameters, and then look at the decompilation results. You will find that the two constructor methods are very similar, if you change the content of the two constructor methods to the same one, The Decompilation will generate the same one. This can be used to explain the construction order at the beginning of this article. In the constructor, the judgment of this call is completed in the compilation phase, rather than in the running stage (the meaning in the description seems to be that this judgment is performed at runtime ).
You may not believe another detail of the construction process, that is, the second record in the sequence that grants default values to non-static members (the memory allocation cannot be verified, which is automatically completed by the Java Virtual Machine ), you can use system at the beginning of the cmethod method of the Child class. out. println (cm3) prints the value of cm3 (the output is 0, the value of other types of members can be obtained through a similar method ).

Next, we will explain another unsolved problem: when will the static member initialization and static initialization block execution be completed? This can be inferred from a small experiment: It is performed when this class object is used for the first time (note that it is a class object rather than a class instance, public and static members of a class can be accessed directly through the class name without generating a class instance. This is the use of class objects instead of class instances, if this class object is not used before the first class instance is generated, before constructing the first class instance, construct the Class Object (that is, initialize the static member and execute the static initialization block), and then execute the construction process of the above class instance ), the test procedure is as follows:
1. modify the main method. out. println (child. scm1) and c = new child (10) are commented out (do not delete, these two statements need to be used later). Compile and run the program, and the output will only include program start and program end, this indicates that no class object is used and no static member is constructed when class instances are generated.
2. set system. out. println (child. scm1). After compilation and running, the execution output of the static initialization block with the parent class and the subclass is added. (using the Class Object of the subclass will generate the Class Object of the parent class, parent class is constructed prior to subclass ).
3. set system. out. println (child. scm1) Comment out and cancel c = new child (10) comments. After compilation and running, the output is only one less than when no statement is commented at the beginning (the output is child. scm1 value 10)

From the above experiments, we can draw the conclusion above.
This article can be said to end now. As my java skills are not very solid and the Java specifications are not complete, there may be errors in this article. If you think there are errors in some places, contact us via mail.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.