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

33,116

Solution 1

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);
    }
}

Solution 2

Other responses have mostly covered the question. If it helps wrap a brain around it, how about an example?

The chicken-and-egg problem is resolved as any recursive problem is: the basis case which doesn't keep producing more work / instances / whatever.

Imagine you've put together a class to automatically handle cross-thread event invocation when necessary. Heavily relevant for threaded WinForms. Then you'd like the class to expose an event which occurs whenever something registers or unregisters with the handler, and naturally it should handle cross-thread invocation as well.

You could write the code that handles it twice, once for the event itself and once for the status event, or write once and re-use.

The majority of the class has been trimmed out as it isn't really relevant to the discussion.

public sealed class AutoInvokingEvent
{
    private AutoInvokingEvent _statuschanged;

    public event EventHandler StatusChanged
    {
        add
        {
            _statuschanged.Register(value);
        }
        remove
        {
            _statuschanged.Unregister(value);
        }
    }

    private void OnStatusChanged()
    {
        if (_statuschanged == null) return;

        _statuschanged.OnEvent(this, EventArgs.Empty);
    }


    private AutoInvokingEvent()
    {
        //basis case what doesn't allocate the event
    }

    /// <summary>
    /// Creates a new instance of the AutoInvokingEvent.
    /// </summary>
    /// <param name="statusevent">If true, the AutoInvokingEvent will generate events which can be used to inform components of its status.</param>
    public AutoInvokingEvent(bool statusevent)
    {
        if (statusevent) _statuschanged = new AutoInvokingEvent();
    }


    public void Register(Delegate value)
    {
        //mess what registers event

        OnStatusChanged();
    }

    public void Unregister(Delegate value)
    {
        //mess what unregisters event

        OnStatusChanged();
    }

    public void OnEvent(params object[] args)
    {
        //mess what calls event handlers
    }

}

Solution 3

The main thing I always see myself creating an instance from within the class, is when I am trying to reference a non-static item in a static context, such as when I am making a frame for a game or whatever, I use the main method to actually set up the frame. You can also use it for when there is something in a constructor that you want to set (like in the following, I make my JFrame not equal to null):

public class Main {
    private JFrame frame;

    public Main() {
        frame = new JFrame("Test");
    }

    public static void main(String[] args) {
        Main m = new Main();

        m.frame.setResizable(false);
        m.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        m.frame.setLocationRelativeTo(null);
        m.frame.setVisible(true);
    }
}
Share:
33,116
Jack_of_All_Trades
Author by

Jack_of_All_Trades

Mechanical Engineer working in Quality control with interests in Python,Javascript and web-technologies.

Updated on July 18, 2020

Comments

  • Jack_of_All_Trades
    Jack_of_All_Trades almost 4 years

    What makes it possible to create a instance of class inside of the class itself?

    public class My_Class
     {
    
          My_Class new_class= new My_Class();
     }
    

    I know it is possible and have done it myself but I cannot still make myself believe that this is not something like " who was first--Chicken or egg ?" type of problem. I could be glad to receive an answer that will clarify this from programming perspective as well as from JVM/ compiler perspective. I think understanding this will help me clear some very important bottleneck concepts of OO programming.

    I have received some answers but none are clear to the degree I expected.

  • Jack_of_All_Trades
    Jack_of_All_Trades over 10 years
    Does that mean that the expressions inside the class definition that creates the instance of its own class is not executed/ compiled before the other expressions? You said, the class is already defined at this point and that is true but how can the instance be able to access the method that is not defined up to that point. Can you please elaborate your answer little to explain this to somebody who has always used interpreted language (meaning the code executes line by line)
  • Joni
    Joni over 10 years
    All methods, constructors, and other members are defined when the class is defined, before any of the code in the class is executed.
  • Jack_of_All_Trades
    Jack_of_All_Trades over 10 years
    Please clear my confusion here, Isn't the instance of the class of the own class also the member of the class in my code above? I am trying to clear my thoughts, Joni.
  • Joni
    Joni over 10 years
    Members are things like variables and methods. A member variable may hold an instance of an object. Instance of classes are not member variables, but a member variable may hold an instance of a class. Just like an int variable is not an integer, but may hold one. Makes sense?
  • Servy
    Servy over 10 years
    That's only true if it's done in the constructor, for the same constructor, and unconditionally, as it results in infinite recursion. If it's done outside of the constructor (say, in a Clone method) then this doesn't apply. If it's done conditionally, then it's recursion, but not infinite recursion.
  • Habib
    Habib almost 9 years
    @Servy, instantiating the same class object at the time of declaration will also cause infinite recursion and stackoverflow exception. It is not just the constructor. This code (same as question) will give Stack overflow exception at runtime public class My_Class{My_Class new_class = new My_Class();}, plus I am not sure if java behaves differently, but in C#, it would be an exception.
  • Servy
    Servy almost 9 years
    @Habib Well, field initializers are moved to the constructor, but yes, if you wanted to be explicit, creating an instance of a class as an instance field initializer (if it's not conditional) would be infinite recursion.