Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the order of class initialization and instantiation of java inheritance relationships

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

In this issue, the editor will bring you about the order of class initialization and instantiation of java inheritance relations. The article is rich in content and analyzes and describes for you from a professional point of view. I hope you can get something after reading this article.

Just like a comment before. What we learn is thinking. Many people know the order in which classes of inheritance relationships are initialized and instantiated, but what if they forget? How to find your own answer? And if the problem encountered is about the erasure of generics, how to analyze it?

Train of thought, the key point is train of thought. Forget about generic erasure. Look at inheritance. First of all, give an example to see what its output is.

Public class A {private static String a = "NA"; private String I = "NA"; {I = "A"; System.out.println (I);} static {a = "Static A"; System.out.println (a);} public A () {System.out.println ("Construct A") }} public class B extends A {private static String b = "NB"; private String j = "NB"; {j = "B"; System.out.println (j);} static {b = "Static B"; System.out.println (b) } public B () {System.out.println ("Construct B");}} public class C {public static void main (String [] args) {new B ();}}

The above output is:

Static A

Static B

A

Construct A

B

Construct B

It's all because of the java compiler. JVM is only responsible for parsing bytecode. Although bytecode is not the most original atomic assembly code, bytecode can fully explain the instruction execution process of JVM. Generally speaking, there is a big difference between bytecode and java source code. Javac will do early optimization to modify and delete source code to generate bytecode that can be understood by jvm interpreter. Java syntax brings security, easy to use, easy to read and other functions let us ignore the byte code will have a way out with java source code.

When new is encountered, such as new B (), it will try to initialize class B. If B has been initialized, start instantiating class B. If class B is not initialized, class B is initialized, but class B inherits A, so class A needs to be initialized before initializing class B. So the initialization process of the class is: a-> B. Class executes static fields and blocks at initialization time. Class instantiation after class initialization, the parent class must be instantiated first. Instantiation executes fields and blocks before executing constructors.

If you rely on this kind of rote learning, the above theory will always be forgotten. Oh, and the constructor of the parent class must be placed on the * line of the subclass constructor. Why?

When you encounter this kind of grammar problem, it is better to read the textbook and find out the answer yourself. The tool is in JDK, a command named javap. Javap will type out a class bytecode pseudo code. We only need to analyze the bytecode of B to find the answer.

JoeytekiMacBook-Air:bin joey$ javap-verbose B Compiled from "B.java" public class B extends A SourceFile: "B.java" minor version: 0 major version: 50 Constant pool: const # 1 = class # 2; / / B const # 2 = Asciz B; const # 3 = class # 4; / / A const # 4 = Asciz A; const # 5 = Asciz b; const # 6 = Asciz Ljava/lang/String;; const # 7 = Asciz j Const # 8 = Asciz; const # 9 = Asciz () V; const # 10 = Asciz Code; const # 11 = String # 12; / / NB const # 12 = Asciz NB; const # 13 = Field # 1.Eng 14; / B.blur Ljava Lancet Lang string; const # 14 = NameAndType # 5 purse 6 Field Lang string; const # 15 = String # 16; / / Static B const # 16 = Asciz Static B Const # 17 = Field # 18.020; / / java/lang/System.out:Ljava/io/PrintStream; const # 18 = class # 19; / / java/lang/System const # 19 = Asciz java/lang/System; const # 20 = NameAndType # 21Vera 22 / out:Ljava/io/PrintStream; const # 21 = Asciz out; const # 22 = Asciz Ljava/io/PrintStream;; const # 23 = Method # 24.026 / / java/io/PrintStream.println: (Ljava/lang/String;) V const # 24 = class # 25; / / java/io/PrintStream const # 25 = Asciz java/io/PrintStream; const # 26 = NameAndType # 27 = NameAndType # 27 const # 27 = Asciz println; const # 28 = Asciz (Ljava/lang/String;) V; const # 29 = Asciz LineNumberTable; const # 30 = Asciz LocalVariableTable; const # 31 = Asciz Const # 32 = Method # 3.Ljava 33; / / A. "": () V const # 33 = NameAndType # 31 const 9 bang bang / "": () V const # 34 = Field # 1.Eng 35; / B.jvvljljlug Ljava Lang string; const # 35 = NameAndType # 7 ljjljljljljljljljljljljljljljljjljjljjljljljljljljljljljljljljjljljjljljljljjljljljljljljljljljjljljljljljljljljlnlangString; const # 36 = String # 2; / / B const # 37 = String # 38 / / Construct B const # 38 = Asciz Construct B; const # 39 = Asciz this; const # 40 = Asciz LB;; const # 41 = Asciz SourceFile; const # 42 = Asciz B.java; {static {}; Code: Stack=2, Locals=0, Args_size=0 0: ldc # 11; / / String NB 2: putstatic # 13; / / Field bvljavaLanguage Langram string; 5: ldc # 15 / / String Static B 7: putstatic # 13; / / Field bazaar Ljava invokevirtual Lang string; 10: getstatic # 17; / / Field java/lang/System.out:Ljava/io/PrintStream; 13: getstatic # 13; / / Field bazaL Ljava Ljava Lang string; 16: invokevirtual # 23; / / Method java/io/PrintStream.println: (Ljava/lang/String ) V 19: return LineNumberTable: line 3: 0 line 11: 5 line 12: 10 line 13: 19 public B (); Code: Stack=2, Locals=1, Args_size=1 0: aload_0 1: invokespecial # 32; / / Method A. ": () V 4: aload_0 5: ldc # 11; / / String NB 7: putfield # 34; / / Field j:Ljava/lang/String 10: aload_0 11: ldc # 36; / / String B 13: putfield # 34; / / Field JJV Ljava Ljava Lang Lang string; 16: getstatic # 17; / / Field java/lang/System.out:Ljava/io/PrintStream; 19: aload_0 20: getfield # 34; / / Field J15 Ljava Ljava Lang string; 23: invokevirtual # 23 / / Method java/io/PrintStream.println: (Ljava/lang/String;) V 26: getstatic # 17; / / Field java/lang/System.out:Ljava/io/PrintStream; 29: ldc # 37; / / String Construct B 31: invokevirtual # 23; / / Method java/io/PrintStream.println: (Ljava/lang/String ) V 34: return LineNumberTable: line 15: 0 line 4: 4 line 6: 10 line 7: 16 line 16: 26 line 17: 34 LocalVariableTable: Start Length Slot Name Signature 0350 this LB;}

The life cycle of a class will go through loading, linking, initializing, using, and unloading the class. Loading reads the bytecode into the method area of memory, while class initialization executes the code of the static {} block in the thread stack. Previously, this block had another name, the class initialization method. Now it has been renamed static {}. Class initialization occurs only once. However, whenever a class is loaded and linked, through bytecode analysis, the JVM parser already knows that B inherits A, so class An initializes before initializing class B. This is a recursive process. Therefore, initialization of class B causes class A static {} execution, followed by B static {} execution. Let's see what is executed in the static {} block of B.

Static {}; Code: Stack=2, Locals=0, Args_size=0 stack depth is 2, 0 local variables, 0 parameters passed. 0: ldc # 11; / / String NB puts # 11 in the constant pool on top of the stack. # 11 = "NB". 2: putstatic # 13; / / Field bjar Ljava static NB string; assign the value "NB" at the top of the stack to # 13 in the constant pool, that is, Ljava b = "NB". 5: ldc # 15; / / String Static B puts # 15 on top of the stack. # 15 = "static B" 7: putstatic # 13; / / Field bjar Ljava Langua Lang string; assign static b = "static B". 10: getstatic # 17; / / Field java/lang/System.out:Ljava/io/PrintStream; stacks PrintStream references. 13: getstatic # 13; / / Field static b Ljava Langua Lang string; stack the value of LJava b. 16: invokevirtual # 23; / / Method java/io/PrintStream.println: (Ljava/lang/String;) V calls the virtual function PrintStream.println ("static B") 19: return exits the function and destroys the function stack frame.

Through annotations, we see that the staticfield assignment and static block in class B are put into the class initialization function.

When we instantiate a class, we call the constructor of the class. Let's see what the constructor of class B does.

Public B (); Code: Stack=2, Locals=1, Args_size=1 stack depth 2, local variable 1 (actually this), parameter 1 (this). 0: aload_0 pushes * * parameters on the stack. That is, this pushes the stack. 1: invokespecial # 32; / / Method A. "": () V calls the constructor of the parent class on this. Super () is not declared in B's constructor, but the java compiler automatically generates this bytecode to call the parent class's no-argument constructor. If super (int) is declared in class B, the compiler will use the corresponding class A constructor instead of .JVM only executes bytecode, it does not constrain super, it is the compiler of java. This stack that constrains them. 4: aload_0 will stack this. 5: ldc # 11; / / String NB stacks "NB". 7: putfield # 34; / / Field this.j= Ljava Ljava Universe string; assign j a value of "NB". This and "NB" are out of stack. 10: aload_0 stacks this. 11: ldc # 36; / / String B puts "B" on stack 13: putfield # 34; / / Field Field Ljava, Ljava and Lang string; assign j the value of "B". This and "B" go out of the stack. Stack empty 16: getstatic # 17; / / Field java/lang/System.out:Ljava/io/PrintStream; stack PrintStream 19: aload_0 stack this 20: getfield # 34; / / Field jazza Ljava this.j Lang string; this off the stack, call this.j, stack this.j. 23: invokevirtual # 23; / / Method java/io/PrintStream.println: (Ljava/lang/String;) V calls PrintStream.println (this.j). The stack is empty. 26: getstatic # 17; / / Field java/lang/System.out:Ljava/io/PrintStream; stack PrintStream 29: ldc # 37; / / String Construct B stack "Construct B" 31: invokevirtual # 23; / / Method java/io/PrintStream.println: (Ljava/lang/String;) V calls PrintStream.println ("Construct B") 34: return

From the bytecode above, it can be seen that when compiling and generating bytecode, the java compiler combines the constructor of the parent class, the initialization of the domain, the execution of the code block and the real constructor of B in order to form a new constructor. The compiled constructor numeric section code of a class must contain the following in this order:

Constructor of the parent class->

Domain initialization of the current class-> (in writing order)

Code block-> (in writing order)

The constructor of the current class.

At this point, you should have a thorough understanding of the order of initialization and instantiation of inherited classes.

The above is the order of class initialization and instantiation of java inheritance relationship shared by Xiaobian. If you happen to have similar doubts, please refer to the above analysis to understand. If you want to know more about it, you are welcome to follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report