0

I am experiencing a seemingly odd problem, although I understand there is probably some reason behind this design, and would like to find out why it is this way.

Consider two classes, Foo and Bar. Bar extends Foo and overrides a method that Foo implements. Foo is quite simple:

public class Foo {
    public Foo() {
        System.out.println("Foo constructor");
        someMethod();
    }

    public void someMethod() {
        System.out.println("Foo.someMethod");
    }
}

Bar is where the problem is. It defines an array which is initialized outside the constructor (I don't know what the term is for this). I noticed that when someMethod is called from Foo, the array has not yet been initialized, but when right after the call to super(), the array IS initialized. Here is Bar:

public class Bar extends Foo {
    int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    public Bar() {
        super();
        System.out.println("FooBar constructor");
        if (a == null) System.out.println("FooBar a is null");
    }

    public void someMethod() {
        if (a == null) System.out.println("FooBar.someMethod a is null");
    }
}

This doesn't quite make sense. I want to access the array from a method which is called in the super constructor, but the array isn't initialized. I have tried to think of a solution. My first idea was to initialize the array in Bar's constructor, but that still won't initialize it before the call to super.

For reference, the output is as follows:

Foo constructor
FooBar.someMethod a is null
FooBar constructor

Why is Java designed like this, and what is the best way around it?

mejdev
  • 3,509
  • 4
  • 24
  • 38
  • 1
    `This doesn't quite make sense.` Why do you think so? Does any part of me exist when my father is born? – Sotirios Delimanolis May 20 '14 at 22:45
  • 1
    Also, this [What's wrong with overridable method calls in constructors?](http://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors?rq=1) will answer most of your questions. – Sotirios Delimanolis May 20 '14 at 22:47
  • Further to the above, it is just a syntactic sugar: the initialization of the array takes place in the constructor of `Bar` and the very first call there must be to the super constructor. Therefore, by the time `super` is called the data are not yet initialised – Oleg Sklyar May 20 '14 at 22:50
  • It's the way it is. Initialization calls the super constructor, then inits the array, then calls the sub constructor. – Hot Licks May 20 '14 at 23:03
  • You can actually change it by moving the init of a into the sub constructor, then having the sub constructor call `super()` *after* the array has been inited. – Hot Licks May 20 '14 at 23:05
  • @Hot Licks, super() has to be the first statement in a constructor though. – mejdev May 20 '14 at 23:08
  • @Vi3GameHkr - No, not really (or at least it doesn't have to be the first thing in the bytecodes during verification - the compiler has its own rules). The conditions for what can go ahead of `super()` are pretty arcane, but I'm pretty sure an array init would be allowed. – Hot Licks May 20 '14 at 23:22
  • @Vi3GameHkr - Apparently you're right -- javac rejects anything ahead of `super()`, even though the verifier would allow some operations. – Hot Licks May 20 '14 at 23:29

2 Answers2

4

The superclass constructor must finish successfully before the rest of the subclass constructor begins. Only then will subclass variables be initialized, so during the superclass constructor, a in Bar is still null. This curious situation arises because a method called by a superclass constructor is overridden in the subclass, so a subclass method is called before the subclass is itself initialized.

For more info on why it's bad Java leaking this in constructor. This lets an object that is not fully initialized be accessible to other objects.

The best thing to do here is not to have the superclass constructor call a method that gets overridden in a subclass. Let Bar do its own initialization/manipulation of a if it would like.

Community
  • 1
  • 1
rgettman
  • 176,041
  • 30
  • 275
  • 357
1

The constructor for the superclass must complete before anything is done in the subclass constructor. This will include any initialization.

David Thielen
  • 28,723
  • 34
  • 119
  • 193