开发者

Java unclear result

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

public cl开发者_Go百科ass 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.


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.


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.


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);
     }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜