1

There is a Class with inner classes. I expected that the output would be 6 9 but suddenly it gave me 0 9. I wonder why I got such unexpected results?
It seems like in A class the f1 variable somehow becomes zero.
Why does this happen?

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

public static class A {
    private int f1 = 7;

    public A(int f2) {
        this.f1 = f2;
        initialize();
    }

    protected void initialize() {
        System.out.println(f1);
    }
}

public static class B extends A {
    protected int f1 = 3;

    public B(int f1) {
        super(f1);
        this.f1 += f1;
        initialize();
    }

    protected void initialize() {
        System.out.println(f1);
    }
}
Idos
  • 15,053
  • 14
  • 60
  • 75
kurumkan
  • 2,635
  • 3
  • 31
  • 55

1 Answers1

2

Class field assignment comes after the call to super(). This is why you are getting the 0.
The call super(f1) occurs before the assignment protected int f1 = 3;. And the default value for int (primitive type) is 0.

And as you know the function initialize() is overridden in B which is where it is executed.

Edit: As for the discussion in the comments, I found some nice reference from Effective Java 2nd Edition, Item 17: Design and document for inheritance, or else prohibit it:

There are a few more restrictions that a class must obey to allow inheritance. Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will be invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected.

Idos
  • 15,053
  • 14
  • 60
  • 75
  • Shouldn't the `super(f1)` call use the _local_ variable `f1` (that has value 6), instead of `this.f1`? – Mick Mnemonic Feb 24 '16 at 18:31
  • I didn't reference this in my answer because I am only concentrating it on the `0` part which is what the OP wondered about. But for your question, no, it uses the 6 that was passed from the instantiation (which is why we got the 9 printed after the 0). – Idos Feb 24 '16 at 18:32
  • Okay, but you're saying that the `initialize()` call in the constructor of `A` resolves to `B.initialize()`, not to `A.initialize()`? – Mick Mnemonic Feb 24 '16 at 18:39
  • Yeah sorry if I was unclear/misleading. My point is that the `f1` that is eventually printed as `0` is in the `initialize()` of `B` and it is the *local* one to `B`. – Idos Feb 24 '16 at 18:40
  • I find it interesting and counter-intuitive that a method call that's done while constructing the object (from the super classes constructor) can be dispatched to the subclass implementation. You'll get my vote if you can find the corresponding JLS reference:) – Mick Mnemonic Feb 24 '16 at 18:44
  • Thank you for the answer. I really can't find any documentation about why it turns like that. – kurumkan Feb 24 '16 at 18:51
  • Never mind, as it's stated in the suggested duplicate, this is one of Java's peculiar features and an obvious reason why one should never call non-final methods from the constructor. – Mick Mnemonic Feb 24 '16 at 19:00
  • Oh @MickMnemonic I just saw that you actually found some nice other question which is very similar (dunno if duplicate though). It explains this very well imo. – Idos Feb 24 '16 at 19:30
  • 1
    The Effective Java quote suffices :) – Mick Mnemonic Feb 25 '16 at 08:18