I don't understand the logic of why the code results in stackOverFlow error:
public class Human {
private String name;
private int age = 30;
private Human human = new Human();
public Human() {
System.out.println("hello world");
}
public static void main(String[] args) {
Human h = new Human();
}
}
Please correct me if i'm wrong. When we write:
Human h = new Human();
The main method and the h reference variable will be pushed into the stack. Then the new keyword will first create a human object with the default values, that is a human object with the field: name = null, age = 30 will be created... BUT once the JVM encounters:
private Human human = new Human();
Then the human reference variable will be pushed into the stack. Then the new keyword will create a human object again with the default values: name = null , age = 30 and then when the JVM encounters:
private Human human = new Human();
Then the human reference variable will again be pushed into the stack and then the new keyword will again created a new human object with the default values etc.
PLESE NOTE: I haven't mentioned the constructor because the constructor is invoked after a human object has been created with all its default values hence when i execute the program, "hello world" (the body of the constructur) is NOT printed into the console...
So, what i am saying is: The reason of why the program results in stackOverFlow error is because of the reference variable human and not because of a lot of constructor invocations.
However, everywhere i read about this example, they always say that it is because of a lot of constructor invocations that results in stackOverFlow error.... constructors initialize the state of an object but how in the world can a constructor initialize an object if the object hasn't even been created yet ? that is why i believe that first the new keyword creates an object with the default values and THEN the constructor initialize the state of that object... but with that in mind, i cannot understand how it is the constructor that is the reason of the stackOverFlow error
When i tested the program for the first time, i expected OutOfMemoryError because the program leads to a lot of human objects being created... however, the program also results in a lot of human reference variables being pushed into the stack (and the stack has a fixed size i believe whereas the heap can grow so it makes sense that the program results in stackOverFlow before OutOfMemoryError).
If I understand correctly, your question fundamentally stems from a misunderstanding of how constructors and inline field initialization work. When you have the following:
The inline initialization of the
ageandhumanfields happen during construction. The byte-code initializing those fields is quite literally in the constructor, despite the source code making it appear otherwise. In other words, the above is equivalent to the following:As you can see, the
Humanconstructor is recursively invoking the same constructor on line 10. A new stack frame is allocated for the calling thread every time this constructor is invoked. Eventually the thread runs out of stack memory and aStackOverflowErroris thrown. And since the error is thrown on line 10, you will not see "Hello, World!" printed to the standard output stream, because line 11 will never be reached.As an aside, note that the default values1 for fields are set before the constructor is invoked. At a high level2, when you use
newthe following happens:Memory is allocated for the new object based on the object's type.
All instance fields of the object are set to their default values by the JVM.
The constructor is invoked.
Unless the current constructor is for
java.lang.Object, the superclass's constructor is invoked, going back to step 3.All instance initializer blocks and inline instance field initializations defined for the current class are invoked in the order they appear in the source code.
The code explicitly in the constructor body is invoked.
The constructor returns.
In the
Humanexample above, the constructor is recursively constructing moreHumanobjects at step 5.1. The default values are:
nullfor object types;0for number primitives; andfalsefor booleans.2. It can get a little more complex than this due to constructors being able to delegate to other constructors and choose which super constructor gets invoked. However, both delegating to other constructors and explicitly invoking a super constructor must be the first statement of the constructor**. That means the superclass's constructor will have been invoked before step 5.
** At least for now. See JEP 447: Statements before super(...) (Preview) (such statements will not be allowed to reference
this; they are meant to facilitate argument validation before invoking a super constructor).