How Does Creating a Instance of Class Inside of the Class Itself Works

How does creating a instance of class inside of the class itself works?

There is absolutely no problem in creating instances of a class in the class itself. The apparent chicken-or-egg problem is solved in different ways while the program is being compiled and when it is being run.

Compile-time

When a class that creates an instance of itself is being compiled, the compiler finds that the class has a circular dependency on itself. This dependency is easy to solve: the compiler knows that the class is already being compiled so it won't try to compile it again. Instead, it pretends that the class already exists generates code accordingly.

Run-time

The biggest chicken-or-egg problem with a class creating an object of itself is when the class does not even exist yet; that is, when the class is being loaded. This problem is resolved by breaking class loading into two steps: first the class is defined and then it is initialized.

Defining means registering the class with the runtime system (JVM or CLR), so that it knows the structure that objects of the class have, and what code should be run when its constructors and methods are called.

Once the class has been defined it is initialized. This is done by initializing static members and running static initializer blocks and other things defined in the particular language. Recall that the class is already defined at this point, so the runtime knows what objects of the class look like and what code should be run to create them. This means there's no problem whatsoever to create objects of the class when initializing it.

Here's an example that illustrates how class initialization and instantiation interact in Java:

class Test {
static Test instance = new Test();
static int x = 1;

public Test() {
System.out.printf("x=%d\n", x);
}

public static void main(String[] args) {
Test t = new Test();
}
}

Let's step through how the JVM would run this program. First the JVM loads the Test class. This means that the class is first defined, so that the JVM knows that

  1. a class called Test exists and that it has a main method and a constructor, and that
  2. the Test class has two static variables, one called x and another called instance, and
  3. what is the object layout of the Test class. In other words: what an object looks like; what attributes it has. In this case Test doesn't have any instance attributes.

Now that the class is defined, it is initialized. First of all, the default value 0 or null is assigned to every static attribute. This sets x to 0. Then the JVM executes the static field initializers in the source code order. There are two:

  1. Create an instance of the Test class and assign it to instance. There are two steps to instance creation:
    1. First memory is allocated for the object. The JVM can do this because it already knows the object layout from the class definition phase.
    2. The Test() constructor is called to initialize the object. The JVM can do this because it already has the code for the constructor from the class definition phase. The constructor prints out the current value of x, which is 0.
  2. Set static variable x to 1.

Only now the class has finished loading. Notice that the JVM created an instance of the class, even though it was not fully loaded yet. You have proof of this fact because the constructor printed out the initial default value 0 for x.

Now that the JVM has loaded this class, it calls the main method to run the program. The main method creates another object of class Test - the second in the execution of the program. Again the constructor prints out the current value of x, which is now 1. The full output of the program is:

x=0
x=1

As you can see there is no chicken-or-egg problem: the separation of class loading into definition and initialization phases avoids the problem completely.

What about when an instance of the object wants to create another instance, like in the code below?

class Test {
Test buggy = new Test();
}

When you create an object of this class, again there is no inherent problem. The JVM knows how the object should be laid out in memory so it can allocate memory for it. It sets all the attributes to their default values, so buggy is set to null. Then the JVM starts initializing the object. In order to do this it must create another object of class Test. Like before, the JVM already knows how to do that: it allocates the memory, sets the attribute to null, and starts initializing the new object... which means it must create a third object of the same class, and then a fourth, a fifth, and so on, until it either runs out of stack space or heap memory.

There is no conceptual problem here mind you: this is just a common case of an infinite recursion in a badly written program. The recursion can be controlled for example using a counter; the constructor of this class uses recursion to make a chain of objects:

class Chain {
Chain link = null;
public Chain(int length) {
if (length > 1) link = new Chain(length-1);
}
}

Create an instance of a class in the class itself

The code in your second fragment cannot compile, because the class Node is not completely defined at the point where you declare its data member x of Node type.

For the sake of understanding, imagine if it could compile, it would lead to some sort of "infinite recursion structure", that would take an infinite amount of memory.
Here's the hypothetical layout of such a class object:

{
data: int
x: Node
{
data: int
x: Node
{
data: int
x: Node
{
...
}
}
}
}

The first case works because you do not need a class to be fully defined in order to declare a pointer to it.

I find that thinking of "fully defined" as "the compiler knows how big this class is" helps to reason about problems like this: the compiler needs to know how big a class is to declare an instance of it, but not to declare a pointer to it, which has the same size regardless of the class.

What happens when we create an instance of class in same class?

Its not a problem. For example:

public class Class1
{
public Class1 Instance {get; set;}
}

public class Class2
{
public void Test()
{
Class1 class1 = new Class1();
var nestedInstance = class1.Instance;
}
}

Please read about singleton pattern: https://msdn.microsoft.com/en-us/library/ff650316.aspx
This let you to understand this case

Instance of class inside of the class itself

As @Lucas mentions in comments, this causes an infinite loop of creation of Person.

You can not construct a Person without initializing the p field, which constructs a Person, which constructs a Person, etc...

Which of course, eventually results in a StackOverflowException.

Instance of the class inside itself

It sounds like you really wish your instance method was static; it should have been static from the start since it doesn't rely on using any internal state of the object (since your new method isn't being given, giving, or re-using any instance of that type). You just can't make the breaking change to make it static because there are too many dependencies using it in a non-static context.

If you can't change the method to be static even though it logically is, your solution is indeed the best you can do in the situation. It's essentially creating a static "window" into the non-static method.

Why can we create an instance of a class inside a static method?

See if these points help you.

1. Execution of a Java program starts with a special method public static void main(String[] args). Since Java is an object oriented language, everything has to be inside class, and this special method main() is no exception. That's why it is inside a class, namely A here.

2.

It just seems wrong to me that I can create an instance of something that I'm still in the process of building

This idea of yours is wrong. When the program is running, everything is built already (surely you know the compilation comes before running), so the notion in the process of building doesn't make any sense when the program is already up and running. And if you associate your statement in the process of building to the building of instance of A, then again that would be wrong, since the main() method is static, so doesn't require an instance of A to exist in order for it to be invoked. In fact, main() is invoked before JVM instantiates any other class in your application.

3.
The main(String[] args) being the starting point of execution, it must be allowed to instantiate some class. Now, your class A is a class just like any other, hence main() can instantiate that too.

Some more reading here:

  1. Why is the Java main method static?
  2. Why make a class create an instance of itself?

When is it OK to create object of a class inside a method of that class?

Is it not strange to create an object in the definition of the same class
than in response the object create a new object then this new object
create another and the infinite loop begins

No, the main method only runs once when you run your program. It will not be executed again. So, the object will be created only once.

Think of your main method to be outside your class. Which creates an instance of your class, and uses the instance created. So, when you create an instance from main method, the constructor is invoked to initialize the state of your instance, and then when the constructor returns, the next statement of your main method is executed.

Actually, you can consider main method not to be a part of the state of the instance of your class.

However, had you created the instance of your class inside your constructor (say 0-arg), and the reference as instance reference variable, then that will turn into an infinite recursion.

public class A {
private A obj;
public A() {
obj = new A(); // This will become recursive creation of object.
// Thus resulting in StackOverflow
}
}

Why Can You Instantiate a Class within its Definition?

You are defining the class, all its fields and methods etc at compile time. The instance is not created until runtime. So there is no contradiction, the class is fully defined by the time you reach line #1.

As others point out, because the main method is static you will reach line #1 without having instantiated an object, but you can do so without issue. I use this pattern all the time for one-class experiments.



Related Topics



Leave a reply



Submit