首页 > 解决方案 > 在父类和子类的构造函数中调用重写方法

问题描述

我在 Java 测试中遇到了一个问题,我错了。请向我解释为什么。

public class A {
    protected String str = "A";
    public static int i = 1;
    public A() {
        foo();
    }
    public void foo() {
        // TODO Auto-generated method stub
        System.out.println(str + " " + i);
    }
}
public class B extends A {
    protected String str = "B";
    public static int i = 2;
    public B() {
        foo();
    }
    public void foo() {
        // TODO Auto-generated method stub
        System.out.println(str + " " + i);

    }
}
public class Program {
    public static void main(String args[]){

                A a = new B();
                B b = new B();
    }
}

在测试中他们问我输出是什么?我回答:“A 1 B 2 A 1 B 2”,但正确答案是:“null 2 B 2 null 2 B 2”你能解释一下为什么吗?

标签: javapolymorphism

解决方案


对于该行A a = new B();,输出是null 2 B 2,因为在隐式运行完成之前,您的类中的实例字段不会被初始化super()

在这种情况下,因为class Bis 扩展构造函数将class A通过调用方法B()隐式调用超类无参数构造函数A()super()foo()

public A() {                                            <---
    foo(); //overriden version in class B is called        |
}                                                          |
                                                           |
public B() {                                               |
    // Static fields are already initialized               |
    // Instance fields are not yet initialized             |
    // Here super() is called implicitly which calls A() ---
    // Instance fields are now initialized to respective values
    foo();
}

的覆盖foo()class B调用,并且在 中foo()被覆盖class B,现在由于super()尚未完成,实例字段class B未初始化并且是null。所以你看到了第一个null 2

然后,当控件退出super()实例初始化程序时,运行 forB然后foo()ofclass B被调用,此时实例字段的实例字段class B被初始化为 value B,因此您会看到B 2打印。

您看不到静态字段的任何问题,因为它们不依赖于super()完成的调用,它们在加载类时被初始化,因此您看到的值i总是初始化和打印而不是null.

line 也是如此B b = new B();

需要注意的重要一点是,您str在 class 中重新定义了 instance 字段B,因此当foo()调用覆盖时,它实际上将引用 class 的 instance 字段B而不是 class 的字段A

考虑这段代码,我str从类中删除了该字段B

class A {
    protected String str = "A";
    public static int i = 1;
    public A() {
        foo();
    }
    public void foo() {
        // TODO Auto-generated method stub
        System.out.println(str + " " + i);
    }
}
 class B extends A {
    public static int i = 2;
    public B() {
        foo();
    }
    public void foo() {
        // TODO Auto-generated method stub
        System.out.println(str + " " + i);

    }
}

当您重新运行程序时,这将打印以下输出:

A 2
A 2
A 2
A 2

发生这种情况是因为super()ofB正在调用构造函数A(),而构造函数又Object()通过自己的super(). 一旦在继承自的实例成员中super()完成所有初始化。现在覆盖将打印出从继承的初始化值。A()BAfoo()strA


推荐阅读