【问题标题】:Java unclear resultJava 不清楚的结果
【发布时间】:2011-09-11 07:15:06
【问题描述】:

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

有人能解释一下结果吗? 您的帮助将不胜感激。

【问题讨论】:

    标签: java variables inheritance initialization overriding


    【解决方案1】:

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

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

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

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

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

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

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

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

    【讨论】:

      【解决方案2】:

      该变量从未在 A 类中初始化,因此它正在打印 prmiitive int 的默认变量,即 0。问题是,尽管在层次结构树上为构造函数调用了 super,但构造函数并没有初始化 i,这是在初始化中完成的,它发生在构造函数之后。

      【讨论】:

      • 不是在构造函数之后——而是编译构造函数体的第一部分调用超类构造函数之后。
      【解决方案3】:

      我不确定您的期望 - 您的示例不会按原样运行,如果它运行了也不会执行任何操作。

      这个例子返回“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);
           }
      }
      

      【讨论】:

      • OP 的代码对我来说编译和运行得非常好,并且打印出 0。您的代码打印出 06 - 从构造函数对 foo() 的调用打印出 0。这只是对 foo() 的调用 打印6的构造函数之后。
      猜你喜欢
      • 2014-11-29
      • 2020-10-19
      • 1970-01-01
      • 2020-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-24
      相关资源
      最近更新 更多