3

I define three classes (A,B,C):

public class A {
     int i = 5;
     public A() {
       foo();
     }
     public void foo() {
       System.out.println(i);
     }
}

class B extends A {
     int i = 6;
}

class C extends B {
        int i = 7;
     public void foo() {
        System.out.print(super.i);
     }
     public static void main(String[] args) {
        C c = new C();
     }
}

expected result is: 6 but program returns: 0

can someone explain the result? your help would be appreciated.

taypen
  • 33
  • 3

3 Answers3

5

Class C overrides A.foo(), and polymorphism is active even in a constructor in Java. Therefore when the constructor in A calls foo() when we're building an instance of C, it's C.foo() that actually gets called.

C.foo() in turn prints out B.i, so we might expect 6 to be printed out - but instance variable initializers are only executed after superclass constructors, so at the point of execution, B.i is 0.

Basically, the order of execution of a constructor is:

  • Execute chained constructors, either explicitly this(...) to chain to another constructor in the same class, or explicitly super(...) to chain to a constructor in the superclass, or implicitly super() to chain to a parameterless constructor in the superclass.
  • For constructors which have chained to a superclass constructor, execute the variable initializers.
  • Execute the code in the constructor body

Rewriting the code to avoid using variable initializers and variable shadowing makes this clearer, while still keeping the code equivalent:

public class A {
  int ai;

  public A() {
    super();
    ai = 5;
    foo();
  }

  public void foo() {
    System.out.println(ai);
  }
}

class B extends A {
  int bi;

  public B() {
    super();
    bi = 6;
  }
}

class C extends B {
  int ci;

  public C() {
    super();
    ci = 7;
  }

  public void foo() {
    System.out.print(bi);
  }

  public static void main(String[] args) {
    C c = new C();
  }
}

As an aside, the "variable hiding" part of this doesn't come into play if you make all your fields private to start with, which is what I'd recommend. That just leaves the issues of calling virtual methods from a constructor, which is generally a bad idea due to expecting an object to be able to work before it's had chance to fully initialize, and the perhaps-surprising timing of variable initializer execution.

If you avoid calling virtual methods from constructors, even the timing of variable initializers becomes irrelevant - at least almost always.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
1

The variable is never initialized in Class A, hence it is printing the default variable for a prmiitive int which is 0. The thing is that although super gets called for the constructors on the hierarchy tree, the constructor does not initialize i, that is done in the initialization, which happens after the constructor.

Oscar Gomez
  • 18,436
  • 13
  • 85
  • 118
  • Not after the constructor - but the first part of the compiled constructor body *after* the call to the superclass constructor. – Jon Skeet Sep 11 '11 at 07:23
0

I'm not sure what you expect - your example won't run as-is, and won't do anything if it did run.

This example returns "6":

public class A {
     int i = 5;
     public A() {
       foo();
     }
     public void foo() {
       System.out.println(i);
     }
     public static void main(String[] args) {
        C c = new C();
        c.foo ();
     }
}

class B extends A {
     int i = 6;
}

class C extends B {
     int i = 7;
     public void foo() {
        System.out.print(super.i);
     }
}
paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • The OP's code compiles and runs perfectly well for me, and prints 0. Your code prints 06 - the call to `foo()` from the constructor prints 0. It's only the call to `foo()` *after* the constructor which prints 6. – Jon Skeet Sep 11 '11 at 07:26