代码之家  ›  专栏  ›  技术社区  ›  chrisTina

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

  •  2
  • chrisTina  · 技术社区  · 6 年前

    对于以下代码,结果是

    我在B中,值为0
    我在B,值是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 是吗?

    2 回复  |  直到 6 年前
        1
  •  7
  •   rgettman    6 年前

    当您不提供对超类构造函数的显式调用时,Java编译器将隐式调用插入到默认超类构造函数中(没有参数)。就好像你的 B 建造师真的是:

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

    对超类构造函数的调用调用 P 构造函数,它调用 diplay .对象实际上是 B 对于多态性, B 复工 方法被调用。

    在这一点上,你有 泄漏 您的子类实例,因为它尚未完全构造。 因为这个, B 的变量 a ,隐藏 P 的变量 ,尚未初始化,因此仍有其默认值, 0 .

    然后是超类 P 构造函数完成,其余的 B 构造函数运行,它还调用 复工 .此调用将看到初始化的 44 值。

    构造函数不调用两次;子类构造函数 B 正在隐式调用超类构造函数 P ,并且两个构造函数都调用 复工 .

    返回 main ,您引用字段 ,但引用位于类型为的变量上 P .没有字段多态性,因此即使对象是 B 在运行时, P 已检索,已将其初始化为 22 .

    这段代码说明了为什么

    1. 泄漏 this 在构造函数完成之前的对象实例,以及
    2. 有意在子类中声明与超类中同名的变量。
        2
  •  1
  •   Ivan    6 年前

    第一,父类的构造函数 class P 被调用。然后打电话来 diplay() .因为您正在创建的实例 class B B::diplay() 称为打印 I am in B, value is 0 因为变量 a 其定义见 B 仅初始化为默认值0和 a = 33 尚未执行。之后 A=33 执行,然后是的构造函数 B 执行和 I am B, value 44 已打印。 以下是所有这些调用的顺序:

    通话顺序如下:

    1.超类静态块*

    2.类的静态块*

    3.超类的非静态块*。

    4.超类构造

    5.非静态块*类

    6.类的构造函数

    https://javacertificationroadmap.com/class-initialization-and-inheritance/