Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StackOverflowError in Instance Initialiser

Tags:

java

theory

This question is more theoretical. So I have this following set of code:

public class Test {

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

    {
        System.out.println("Instance execution");
    }
}

It compiles and prints "Instance Execution". But when I try to execute some other method this way:

public class Test {

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

    {
        System.out.println("Instance execution");
    }

    private void anotherMethod() {
        System.out.println("Method execution");
    }

    {
        Test test = new Test();
        test.anotherMethod();
    }
}

It's giving me this error:

Exception in thread "main" java.lang.StackOverflowError
at Test.<init>(Test.java:15)

I'm totally convinced that this error has the easiest explanation, but my question here, is it the constructor that's throwing this error? Or only System methods can be executed this way? This whole approach of executable Instance Initialiser is very new to me, so any help would be much appreciated. Thanks.

like image 283
Raka Chowdhury Avatar asked Mar 09 '23 09:03

Raka Chowdhury


2 Answers

The Problem is, that you create a Test obejct in your constructor, which will create another Test object and so on. Instead use

this.anotherMethod();
like image 20
Orinion Avatar answered Mar 11 '23 22:03

Orinion


This:

{
    Test test = new Test();
    test.anotherMethod();
}

is an instance initializer block. It runs every time you create a Test instance. Within it, you're...creating a new Test instance, which naturally triggers the block, which then creates a new Test instance, which triggers the block... You get the idea.

is it the constructor that's throwing this error?

It's instance initialization, yes. And in fact, under the covers, the way instance initializer blocks are handled by the compiler is to literally copy that code into the beginning of every constructor in the class (including the default one, if you don't supply a default one), just after any call to super (the default one if there isn't an explicit one). So you could say it's the constructor throwing the error, even if conceptually, it's instance initialization as distinct from the constructor per se.

Or only System methods can be executed this way?

Not sure what you mean by "System methods," but the issue is that the initializer block is run per-instance. If you wanted it run only once, at class initialization time, you could use a static initializer block:

public class Test {

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

    {
        System.out.println("Instance execution");
    }

    private void anotherMethod() {
        System.out.println("Method execution");
    }

    static // <==================
    {
        System.out.println("Class initialization"); // ***
        Test test = new Test();
        test.anotherMethod();
    }
}

That outputs:

Class initialization
Instance execution
Method execution
Instance execution

(We see "Instance execution" twice because there's one new Test in main, and another in the static initializer block.)

But really, the simplest thing is to put the call to anotherMethod in main:

public class Test {

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

    {
        System.out.println("Instance execution");
    }

    private void anotherMethod() {
        System.out.println("Method execution");
    }
}

which outputs

Instance execution
Method execution
like image 74
T.J. Crowder Avatar answered Mar 11 '23 21:03

T.J. Crowder