Java结果不清楚

时间:2011-09-11 07:15:06

标签: java variables inheritance initialization override

我定义了三个类(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();
     }
}

预期结果是:6 但程序返回:0

有人可以解释结果吗? 你的帮助将不胜感激。

3 个答案:

答案 0 :(得分:5)

C会覆盖A.foo(),即使在Java中的构造函数中,多态也是活动的。因此,当A中的构造函数在我们构建foo()的实例时调用C时,它实际上会被调用C.foo()

C.foo()反过来打印B.i,因此我们可能期望 6打印出来 - 但实例变量初始化程序仅在之后执行超类构造函数,因此在执行时,B.i为0。

基本上,构造函数的执行顺序是:

  • 执行链式构造函数,显式this(...)链接到同一个类中的另一个构造函数,或显式super(...)链接到超类中的构造函数,或隐式super()链接到超类中的无参数构造函数。
  • 对于链接到超类构造函数的构造函数,执行变量initializers。
  • 执行构造函数体中的代码

重写代码以避免使用变量初始化器和变量阴影使这更清晰,同时仍保持代码等效:

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

顺便说一句,如果您将所有字段设为私有字体,那么“变量隐藏”部分就不会发挥作用,这就是我建议的。这只留下了从构造函数调用虚方法的问题,这通常是一个坏主意,因为期望一个对象能够在它有机会完全初始化之前工作,以及可能令人惊讶的变量初始化程序执行时间。

如果你避免从构造函数中调用虚方法,那么即使变量初始化器的时间也变得无关紧要 - 至少几乎

答案 1 :(得分:1)

变量永远不会在A类中初始化,因此它打印的是prmiitive int的默认变量,即0。虽然super在层次结构树上调用了构造函数,但构造函数不会初始化i,这是在构造函数之后的初始化中完成的。

答案 2 :(得分:0)

我不确定你的期望 - 你的例子不会按原样运行,如果它运行的话也不会做任何事情。

此示例返回“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);
     }
}