Today, some netizens in A group asked the following question: Why is the stack overflow (StackOverflowError) caused by the code called for running:
public class Constructor { Constructor c = new Constructor(); public static void main(String[] args) { Constructor test = new Constructor(); }}
Ordinary people, at first glance, do not feel any problem, but if they run on the machine, such an error will pop up,
From these errors, we can get the following information: when the program is running, the Constructor instance Initialization Method
(Here is <init>, which will be detailed later.
The people in the group replied to this question. One of the netizens pushed the result through the symptom and said, "In this Constuctor class, because the member c of the class is actually
Constructor type, so when class members are initialized, the class Constructor is called recursively ".
The answer is, to be honest, no logic. It seems like I am confused. In fact, if we start with the bytecode of this class after disassembly,
You can get the answer to the question clearly.
We use java-p Constructor to obtain the deserialization bytecode, as follows:
public class Constructor extends java.lang.Object{
Constructor c;
public Constructor();
Code:
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #1; //class Constructor
8: dup
9: invokespecial #12; //Method "<init>":()V
12: putfield #13; //Field c:LConstructor;
15: return
public static void main(java.lang.String[]);
Code:
0: new #1; //class Constructor
3: dup
4: invokespecial #12; //Method "<init>":()V
7: astore_1
8: return
}
We only need to pay attention to the Code in Constructor of this Constructor. We can find that in this Constructor,
The new #1; // class Constructor statement is displayed, which indicates creating a Constructor type object.
From here we can understand:
Even if you initialize a member such as c explicitly outside the constructor, but when the class is compiled and run,
The real initialization of such Explicit initialization members is still carried out in the constructor in a unified manner.
So the code like the one just now is equivalent to calling itself in the Constructor, just like the following code:
Public class Constructor {
Constructor c;
Public Constructor (){
C = new Constructor ();
}
Public static void main (String [] args ){
Constructor test = new Constructor ();
}
}
How can you avoid stack overflow?
PS: By the way, the meaning of several Bytecode commands is as follows:
Create a new object.
Invokespecial calls the instance method based on the compile-time type.
Invokevirtual calls the instance method based on the actual type of the runtime object.
Putfield sets the field value in the object.