简体   繁体   English

JAVA inheritance 构造函数调用顺序

[英]JAVA inheritance constructor order of call

When I run the following program当我运行以下程序时

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

I expect the following我期待以下

A ctor
B ctor
B ctor
A ctor
A ctor

But instead I get但相反我得到

B ctor
B ctor
B ctor
A ctor
A ctor

I'm confused as to why this is.我很困惑为什么会这样。 The first call to the constructor of B should call Af() (thru the automatic call to A 's constructor) but looks like its calling Bf()B的构造函数的第一次调用应该调用Af() (通过对A的构造函数的自动调用)但看起来像它调用Bf()

Why?为什么?

When you compile B.java , the compiler inserts some code.当您编译B.java时,编译器会插入一些代码。 While you typed.当您键入时。

    B() {
        f();
    }

If you reverse the Java Bytecode, you will clearly see instructions like如果你反转 Java 字节码,你会清楚地看到如下指令

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

But while that might explain the inheritence question, there's a massive problem with your code.但是,虽然这可以解释继承问题,但您的代码存在很大问题。

It is not safe to call functions on a class that's not constructed.在未构造的 class 上调用函数是不安全的。

So calling f() inside of A() is not safe.所以在A() f() ) 是不安全的。 This is because A() isn't full constructed until the constructor of A() completes.这是因为在 A() 的构造函数完成之前, A() A()还没有完全构造。 Again, calling f() inside of B() is not safe, for the same reasons.同样,出于同样的原因,在B() f() ) 也是不安全的。

If you convert f() to static members, which don't use the this references, then you will have safe code;如果您将f()转换为不使用this引用的 static 成员,那么您将拥有安全代码; however, you won't get polymorphisim in your f() calls.但是,您不会在f()调用中获得多态性。

Remember, that a f() call is a call on the object.请记住, f()调用是对 object 的调用。 In the middle of wiring the object's dynamic methods, a call to f() might refer to either A 's or B's implementation, and at the time of construction, it's not always possible to know which one should be invoked, as A() 's constructor is called in an identical manner both inside and outside of the B() constructor.在连接对象的动态方法的过程中,对f()的调用可能会引用AB's实现,并且在构造时,并不总是可能知道应该调用哪一个,因为A()的构造函数在B()构造函数内部和外部都以相同的方式调用。

Now that the general rule has been stated, here's the exceptions:既然已经说明了一般规则,以下是例外情况:

  1. You can safely call some function g() within a constructor if g() is a final member function, which refers to variables that have been properly assigned and final in that class level.如果g()是最终成员 function,您可以在构造函数中安全地调用一些 function g() ,它指的是在 ZA2F2ED4F8EBC2CBB4C21A29DC40AB61 级别中已正确分配和最终的变量。

  2. You can safely call some function h() in a parent class, if h() is written to only mutate variables that are effectively private to the parent class.您可以安全地在父 class 中调用一些 function h() ,如果h()仅写入父 class 有效私有的变异变量。

  3. You can call some function j() in a parent class, if all the variables used by j() have a sensible assignment, but you might not see the desired results if the variables are leaked for mutation to lower sub-classes.如果 j( j()使用的所有变量都具有合理的赋值,您可以在父 class 中调用一些 function j() ,但如果变量因突变而泄漏到较低的子类,您可能看不到所需的结果。

Basically, if you know enough about how classes are constructed, you can write your code to work with the construction order because you're programming your functions around the failure cases.基本上,如果您对如何构造类有足够的了解,则可以编写代码以使用构造顺序,因为您正在围绕失败案例编写函数。 The first two approaches are considered "good design" and the last approach is considered "bad design, but we do it when it works" quality code.前两种方法被认为是“好的设计”,最后一种方法被认为是“糟糕的设计,但我们会在它工作的时候去做”质量代码。

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

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