Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why aren't fields initialized to non-default values when a method is run from super()?

I must have spent over an hour trying to figure out the reason for some unexpected behavior. I ended up realizing that a field wasn't being set as I'd expect. Before shrugging and moving on, I'd like to understand why this works like this.

In running the example below, I'd expect the output to be true, but it's false. Other tests show that I always get whatever that type default value is.

public class ClassOne {

    public ClassOne(){
        fireMethod();
    }

    protected void fireMethod(){
    }

}

public class ClassTwo extends ClassOne {

    boolean bool = true;

    public ClassTwo() {
        super();
    }

    @Override
    protected void fireMethod(){
        System.out.println("bool="+bool);
    }

    public static void main(String[] args) {
        new ClassTwo();
    }
}

output:

bool=false
like image 554
Smig Avatar asked Jul 15 '13 15:07

Smig


2 Answers

boolean bool = true;

public ClassTwo() {
    super();
}

is identical to

boolean bool;

public ClassTwo() {
    super();
    bool = true;
}

The compiler automatically moves the fields initializations within the constructor (just after the super constructor call, implicitly or explicitly).

Since a boolean field default value is false, when super() is called (and thus ClassOne() and fireMethod()), bool hasn't been set to true yet.


Fun fact: the following constructor

public ClassTwo() {
    super();
    fireMethod();
}

will be understood as

public ClassTwo() {
    super();
    bool = true;
    fireMethod();
}

by the JVM, and the output will thus be

bool=false
bool=true
like image 166
sp00m Avatar answered Oct 16 '22 04:10

sp00m


The superclass constructor is called before the subclass constructor. And in Java, before a constructor is run, all instance members have their default value (false, 0, null). So when super() is called, bool is still false (default value for booleans).

More generally, calling an overridable method from a constructor (in ClassOne) is a bad idea for the reason you just discovered: you might end up working on an object that has not been fully initialised yet.

like image 45
assylias Avatar answered Oct 16 '22 03:10

assylias