繁体   English   中英

JAVA inheritance 构造函数调用顺序

[英]JAVA inheritance constructor order of call

当我运行以下程序时

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的构造函数的第一次调用应该调用Af() (通过对A的构造函数的自动调用)但看起来像它调用Bf()

为什么?

当您编译B.java时,编译器会插入一些代码。 当您键入时。

    B() {
        f();
    }

如果你反转 Java 字节码,你会清楚地看到如下指令

    B() {
        super();
        f();
    }

但是,虽然这可以解释继承问题,但您的代码存在很大问题。

在未构造的 class 上调用函数是不安全的。

所以在A() f() ) 是不安全的。 这是因为在 A() 的构造函数完成之前, A() A()还没有完全构造。 同样,出于同样的原因,在B() f() ) 也是不安全的。

如果您将f()转换为不使用this引用的 static 成员,那么您将拥有安全代码; 但是,您不会在f()调用中获得多态性。

请记住, f()调用是对 object 的调用。 在连接对象的动态方法的过程中,对f()的调用可能会引用AB's实现,并且在构造时,并不总是可能知道应该调用哪一个,因为A()的构造函数在B()构造函数内部和外部都以相同的方式调用。

既然已经说明了一般规则,以下是例外情况:

  1. 如果g()是最终成员 function,您可以在构造函数中安全地调用一些 function g() ,它指的是在 ZA2F2ED4F8EBC2CBB4C21A29DC40AB61 级别中已正确分配和最终的变量。

  2. 您可以安全地在父 class 中调用一些 function h() ,如果h()仅写入父 class 有效私有的变异变量。

  3. 如果 j( j()使用的所有变量都具有合理的赋值,您可以在父 class 中调用一些 function j() ,但如果变量因突变而泄漏到较低的子类,您可能看不到所需的结果。

基本上,如果您对如何构造类有足够的了解,则可以编写代码以使用构造顺序,因为您正在围绕失败案例编写函数。 前两种方法被认为是“好的设计”,最后一种方法被认为是“糟糕的设计,但我们会在它工作的时候去做”质量代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM