Join the Stack Overflow Community
Stack Overflow is a community of 6.6 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I just saw this weird piece of code in another question. I thought it would result in a StackOverflowError being thrown, but it does not.

public class Node {
    public static Node NIL = new Node(Node.NIL, Node.NIL);

    public Node(Object one, Object two) {
        // Assign values to fields
    }
}

I thought it was going to explode, because Node.NIL is referencing itself to build.

Can someone explain to me why it does not?

share|improve this question
4  
probably because of static but i am not sure – XtremeBaumer 22 hours ago
15  
What I would expect is that the NIL field is constructed as it it was declared as new Node(null, null), because when the constructor is called, Node.NIL hasn't been set to anything yet. – khelwood 22 hours ago
    
@khelwood yep, based on answer i understood the same think. – Anthony Raymond 22 hours ago
2  
Please never use this in production code. It can provide a nice trivia, but I would consider this to be deliberate obfuscation. – chi 19 hours ago
11  
It won't throw a StackOverflowError because you posted it on Stack Overflow, and that would look bad. Code these days is often context-aware, so if you posted it on (say) Facebook, it might throw a StackOverflowError under those conditions, but would never throw FacebookError. Similarly, code posted on Reddit never triggers a RedditException. Honest! Stop looking at me like that. – Ti Strga 12 hours ago
up vote 50 down vote accepted

NIL is a static variable. It is initialized one time, when the class is initialized. When it is initialized, a single Node instance is created. The creation of that Node doesn't trigger creation of any other Node instances, so there is not infinite chain of calls. Passing Node.NIL to the constructor call has the same effect as passing null, since Node.NIL is not yet initialized when the constructor is called. Therefore public static Node NIL = new Node(Node.NIL, Node.NIL); is the same as public static Node NIL = new Node(null, null);.

If, on the other hand, NIL was an instance variable (and wasn't passed as an argument to the Node constructor, since the compiler would have prevented you from passing it to the constructor in that case), it would be initialized every time an instance of Node was created, which would create a new Node instance, whose creation would initialize another NIL instance variable, leading to infinite chain of constructor calls that would end in StackOverflowError.

share|improve this answer
    
Thanks, you made it clearer, the way it works is still odd to me. But at least i understand why it works this way. – Anthony Raymond 22 hours ago
3  
If NIL was an instance variable, it would not compile with the error Cannot reference a field before it is defined. – Florian Genser 18 hours ago
    
@FlorianGenser Good point. I wrote this part before noticing that Node.NIL was passed to the constructor. – Eran 17 hours ago
2  
java.awt.Color is actually a good demonstration of static variables in action. It has a bunch of different colors, like Color.BLUE, which also contains references to all the other colors... This dazzled me back when I first started in Java. – sfdcfox 16 hours ago
    
Thanks for that @sfdcfox i'll take a look on this. – Anthony Raymond 12 hours ago

The variable NIL is first given the value null and then initialised once top to bottom. It isn't a function and isn't defined recursively. Any static field you use before it is initialised has the default value and your code is the same as

public static Node {
    public static Node NIL;

    static {
        NIL = new Node(null /*Node.NIL*/, null /*Node.NIL*/);
    }

    public Node(Object one, Object two) {
        // Assign values to fields
    }
}

This is no different to writing

NIL = null; // set implicitly
NIL = new Node(NIL, NIL);

If you defined a function or method like this, you would get a StackoverflowException

Node NIL(Node a, Node b) {
    return NIL(NIL(a, b), NIL(a, b));
}
share|improve this answer

The key to understand why it doesn't cause infinite inititialization is that when the class Node is being initialized, the JVM keeps track of it and avoids re-initialization during a recursive reference to the class within its original initialization. This is detailed in this section of the language spec:

Because the Java programming language is multithreaded, initialization of a class or interface requires careful synchronization, since some other thread may be trying to initialize the same class or interface at the same time. There is also the possibility that initialization of a class or interface may be requested recursively as part of the initialization of that class or interface; for example, a variable initializer in class A might invoke a method of an unrelated class B, which might in turn invoke a method of class A. The implementation of the Java Virtual Machine is responsible for taking care of synchronization and recursive initialization by using the following procedure.

So while the static initializer is creating the static instance NIL, the reference to Node.NIL as part of the constructor call does not re-execute the static initializer again. Instead it just references whatever value the reference NIL has at that time, which is null in this case.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.