Java 不清楚的结果

发布于 2024-12-04 06:14:06 字数 465 浏览 0 评论 0原文

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凉风有信 2024-12-11 06:14:06

C 重写A.foo(),并且即使在Java 的构造函数中,多态性也是活跃的。因此,当我们构建 C 的实例时,A 中的构造函数调用 foo() 时,它是 C.foo() 实际上被调用了。

C.foo() 依次打印出 Bi,因此我们可能期望 6 被打印出来 - 但是实例变量初始值设定项仅在超类构造函数之后执行,因此在执行时,Bi 为 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();
  }
}

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

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

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.

冰葑 2024-12-11 06:14:06

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

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.

叫思念不要吵 2024-12-11 06:14:06

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

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

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);
     }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文