java构造函数行为继承和静态/动态绑定

时间:2015-06-26 13:53:13

标签: java inheritance constructor

所以我有以下3个班级:

A" A"使用1个字段和1个调用方法的构造函数:

public class A {
    String bar = "A.bar";

    A() {
        foo();
    }

    public void foo() {
        System.out.println("A.foo(): bar = " + bar);
    }
}

第二课" B"继承自A的1个字段和1个调用方法的构造函数:

public class B extends A {
    String bar = "B.bar";

    B() {
        foo();
    }

    public void foo() {
        System.out.println("B.foo(): bar = " + bar);
    }
}

第三课" C"包含主要方法:

public class C {
    public static void main(String[] args) {
        A a = new B();
        System.out.println("a.bar = " + a.bar);
        a.foo();
    }
}

输出是:

B.foo():bar = null

B.foo():bar = B.bar

a.bar = A.bar

我在调试模式下跟踪了程序,我仍然无法弄清楚输出。我将非常感谢对所发生的过程及其背后的原则的详细解释。 非常感谢。

编辑:就像人们指出我确实忘记了输出的最后一行:

B.foo():bar = B.bar

3 个答案:

答案 0 :(得分:5)

首先调用B类的构造函数。但是,如果扩展一个类而不显式调用基类的构造函数(或派生类的其他构造函数),那么每个默认构造函数的第一行都是super()的(隐藏)调用,即构造函数基类(在本例中为A)。因此,我们继续使用A的构造函数,它调用方法foo()。由于此方法在B类中被覆盖,因此会调用overriden实现。现在事情变得有趣了 - B的构造函数仍然没有完成,所以bar的值仍未设置,因此输出:

B.foo(): bar = null

我们现在回到B&#39的构造函数中,它输出

B.foo(): bar = B.bar

最后,输出

a.bar = A.bar

归因于variable shadowing

答案 1 :(得分:2)

  1. 您调用B
  2. 的构造函数
  3. 在B的构造函数中,A的构造函数被称为隐式
  4. A的构造函数调用方法foo()
  5. 由于方法foo()被覆盖在B上,Java解析为此显式方法并调用此实现 这里有B.foo(): bar = null'因为对象尚未初始化
  6. 然后B的构造函数继续执行并再次调用foo(),然后你有B.foo(): bar = B.bar
  7. 构造函数完成其执行,因此您拥有的下一个字符串来自您的System out。这里因为您使用A类来访问您的实例,并且由于类的属性不能在子类上重写(至少不是这种方式),Java会将bar的值解析为存储在A中的值。
  8. 以下是此

    的文档

    子类属性仅隐藏超类attrs。 https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html

    关于超级作品和超级构造者的一些注释 https://docs.oracle.com/javase/tutorial/java/IandI/super.html

    不要在构造函数中调用可覆盖的方法 https://www.securecoding.cert.org/confluence/display/java/MET05-J.+Ensure+that+constructors+do+not+call+overridable+methods

    P.S。你错过了你提供给我们的输出中的最后一个方法调用

答案 2 :(得分:1)

在超构造函数调用和this-constructor主体之间插入初始化代码。因此B的构造函数非常像

B() 
{
    super(); // A()
    this.bar = "B.bar";
    foo();
}