JAVA继承构造函数调用顺序
当我运行以下程序时JAVA继承构造函数调用顺序,java,inheritance,constructor,Java,Inheritance,Constructor,当我运行以下程序时 public class Example { static class A { A() { f(); } public void f(){ System.out.println("A ctor"); } } static class B extends A { B() {
public class Example {
static class A {
A()
{
f();
}
public void f(){
System.out.println("A ctor");
}
}
static class B extends A {
B()
{
f();
}
public void f() {
System.out.println("B ctor");
}
}
public static void main(String[] args) {
B b = new B();
b.f();
A a = new A();
a.f();
}
}
我期待以下几点
A ctor
B ctor
B ctor
A ctor
A ctor
但是我得到了
B ctor
B ctor
B ctor
A ctor
A ctor
我不明白为什么会这样。对B
的构造函数的第一次调用应该调用A.f()
(通过对A
的构造函数的自动调用),但看起来像它的调用B.f()
为什么?编译
B.java
时,编译器会插入一些代码。你打字的时候
B() {
f();
}
如果您反转Java字节码,您将清楚地看到如下指令
B() {
super();
f();
}
但是,虽然这可以解释继承性问题,但是您的代码存在一个巨大的问题
对未构造的类调用函数是不安全的。
因此,在A()
内部调用f()
是不安全的。这是因为在A()
的构造函数完成之前,A()
不是完全构造的。同样,出于同样的原因,在B()
内部调用f()
也是不安全的
如果将f()
转换为不使用this
引用的静态成员,那么您将拥有安全代码;但是,在f()
调用中不会获得多态性
请记住,f()
调用是对对象的调用。在对对象的动态方法进行布线时,调用<代码>()>代码>可能指的是<代码> A<代码> >或<代码> B <代码>实现,并且在构建时,不可能知道应该调用哪一个,如<代码>()。的构造函数在B()的内部和外部都以相同的方式调用
既然已经说明了一般规则,以下是例外情况:
如果g()
如果将h()
写入仅对父类有效私有的变量进行变异,则可以安全地调用父类中的某个函数h()
如果j()
使用的所有变量都有合理的赋值,则可以调用父类中的某个函数j()
,但如果变量因变异而泄漏到较低的子类,则可能看不到所需的结果
基本上,如果您对类的构造有足够的了解,您可以编写代码来处理构造顺序,因为您正在围绕失败案例编写函数。前两种方法被认为是“好的设计”,最后一种方法被认为是“坏的设计,但我们会在工作时这样做”质量代码。Java中的所有方法都是虚拟的。因此,<代码> B<代码>永远不会调用<代码> A<代码> < <代码>()>代码>。java在这方面与C++不同。你的期望在C++中是正确的,但它不是在java中。在此情况下,Java上的NSTUAI将始终调用覆盖。