Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JAVA继承构造函数调用顺序_Java_Inheritance_Constructor - Fatal编程技术网

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将始终调用覆盖。