java - 扩展类构造函数被调用两次

标签 java constructor

对于以下代码,结果为

I am in B, value is 0
I am in B, value is 44
22

public class Test {
    public static void main(String[] args) {
        P b = new B();
        System.out.println(b.a);
    }

    static class P {
        public int a = 11;

        public P() {
            a = 22;
            diplay();
        }

        public void diplay() {
            System.out.println("I am in P, value is " + a);
        }
    }

    static class B extends P {
        int a = 33;

        public B() {
            a = 44;
            diplay();
        }

        public void diplay() {
            System.out.println("I am in B, value is " + a);
        }
    }
}

首先,为什么构造函数会被调用两次?
为什么b.a 的值为22
最后,为什么第一个a的值为0

最佳答案

只要您不提供对父类(super class)构造函数的显式调用,Java 编译器就会为您插入对默认父类(super class)构造函数的隐式调用(无参数)。就好像您的 B 构造函数实际上是:

public B() {
    super();
    a = 44;
    diplay();
}

对父类(super class)构造函数的调用会调用 P 构造函数,后者又调用 diplay。该对象实际上是一个 B,因此通过多态性,将调用 Bdiplay 方法。

此时,您已经泄漏了您的子类实例,因为它尚未完全构造。因此,B 的变量a,隐藏了P的变量a,还没有被初始化,所以它仍然有默认值,0.

然后,父类(super class) P 构造函数完成,B 构造函数的其余部分运行,同时也会调用 diplay。此调用会看到初始化的 44 值。

构造函数不会被调用两次;子类构造函数 B 隐式调用父类(super class)构造函数 P,并且两个构造函数都调用 diplay

回到main,您引用了字段a,但引用是在P类型的变量上。没有字段多态性,因此即使运行时对象是 B,也会检索到 Pa 值,即初始化为22

此代码说明了为什么通常不是一个好主意

  1. 在构造函数完成之前泄漏 this 对象实例,并且
  2. 有意在子类中声明与父类(super class)中同名的变量。

关于java - 扩展类构造函数被调用两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51073396/

相关文章:

java - 将 VarHandle 转换为 java.lang.reflect.Field

java - 使用构造函数初始化静态字段是否总是被认为是不好的做法?

java - 我可以使用 Inno Setup 为 Java 应用程序创建独立的 .exe 安装程序吗?

java Jpanel 和边框布局,向 PAGE_END 添加 2 个组件

java - 如何通过 RequestFactory 高效使用 RestTemplate?

c++ - 崩溃,可能是由于构造函数或析构函数中的某些问题

c++ - 在C++中,如何正确获取指向 vector 的共享指针,最大限度地减少复制构造函数的调用次数?

arrays - 如何在Scala中将Option数组初始化为None

java - 如何初始化匿名类的对象?

java - 处理资源 xml 文件