Java 继承中的静态块与初始值设定项块与构造函数

Java 继承中的静态块与初始值设定项块与构造函数,java,inheritance,constructor,polymorphism,static-block,Java,Inheritance,Constructor,Polymorphism,Static Block,我找到了这个例子,我想了解它背后的逻辑?构造函数、静态块和初始值设定项块在继承中是如何工作的?在哪个阶段,每一个都被称为 public class Parent { static { System.out.println("i am Parent 3"); } { System.out.println("i am parent 2"); } public Parent() { System.out.pr

我找到了这个例子,我想了解它背后的逻辑?构造函数、静态块和初始值设定项块在继承中是如何工作的?在哪个阶段,每一个都被称为

public class Parent {

    static {
        System.out.println("i am Parent 3");
    }

    {
        System.out.println("i am parent 2");
    }

    public Parent() {
        System.out.println("i am parent 1");
    }

}

public class Son extends Parent {

    static {System.out.println("i am son 3");}
    {System.out.println("i am son 2");}

    public Son() {
        System.out.println("i am son 1");
    }

    public static void main(String[] args) {
        new Son();
    }
}
输出为:

i am Parent 3
i am son 3
i am parent 2
i am parent 1
i am son 2
i am son 1

当类被JVM加载和初始化时,静态块被调用一次。实例初始值设定项是在构造类的实例时执行的,就像构造函数一样


静态和实例初始值设定项在

中描述,当JVM加载和初始化类时,静态块被调用一次。实例初始值设定项是在构造类的实例时执行的,就像构造函数一样


静态和实例初始值设定项在类加载到JVM时执行静态块,而构造函数块在创建实例时执行


静态初始值设定项相当于静态上下文中的构造函数。您肯定会看到,这比实例初始值设定项更常见。

静态块在类加载到JVM时执行,而构造函数块在创建实例时执行


静态初始值设定项相当于静态上下文中的构造函数。您肯定会比实例初始值设定项更经常地看到这一点。

当您的类被加载时,静态块被调用,并且您的类首先由jvm中的classloader加载,所以它们首先被执行


然后,您创建对象,以便调用父init块,然后由于java中的构造函数链接而调用父构造函数,然后在加载类时调用派生类init块,然后调用派生类构造函数

然后创建对象,这样就调用父init块,然后调用父构造函数,这是由于java中的构造函数链接,然后是派生类init块,然后是派生类构造函数

  • 构造函数中的第一条指令是调用其父类的构造函数
    super(params)
    ,或者如果要使用默认构造函数
    super()
    。对于默认构造函数,您不必显式地编写它
  • 初始化程序块中的代码在
    super(…)
    调用之后立即移动到每个构造函数
  • 静态块在类初始化时执行,初始化是在JVM完全加载(及其父类)后完成的
  • 所以类被编译成与此类似的类

    public class Parent {
        static {
            System.out.println("Parent static block");
        }
    
        public Parent() {
            super();
            {
                System.out.println("Parent initializer block");
            }
            System.out.println("Parent constructor");
        }
    
    }
    
    public class Son extends Parent {
    
        static {
            System.out.println("Son static block");
        }
    
        public Son() {
            super();
            {
                System.out.println("Son initializer block");
            }
            System.out.println("Son constructor");
        }
    
        public static void main(String[] args) {
            new Son();
        }
    }
    
    为了能够从
    Son
    类执行
    main
    方法,JVM需要加载此类(及其扩展的类)的代码。类完全加载后,JVM初始化其静态内容,这涉及到执行静态块(是的,一个类中可以有多个静态块)。要完全加载
    Son
    类,JVM需要知道其父类的详细信息,以便在
    Son
    类之前完全加载
    parent
    类,这意味着它还将在
    Son
    类中的静态块之前执行其静态块

    因此,输出将如下所示:

    • 父静态块
    • 子静态块
    现在在
    main
    方法中,通过
    new-Son()
    调用
    Son
    类构造函数

    super();
    {
        System.out.println("Son initializer block");
    }
    System.out.println("Son constructor");
    
    因为它的
    super()
    引用了
    父类构造函数,它是

    super();// this will invoke Object constructor since Parent 
            // doesn't extend anything (which means it extends Object class)
    {
        System.out.println("Parent initializer block");
    }
    System.out.println("Parent constructor");
    
    结果你会看到

    • 父初始值设定项块
    • 父构造函数
    这将处理使用
    super()
    执行的
    Parent#constructor()
    ,因此接下来您将看到子构造函数在
    super()
    之后生成的代码

    • 子初始值设定项块
    • Son构造函数

    要查看在使用
    Son
    constructor或甚至
    main
    方法之前是否会加载类,您可以在使用
    Son
    constructor之前打印一些内容

    System.out.println("ABC                      // before new Son()");
    new Son();
    
    这将导致

    Parent static block
    Son static block
    ABC                      // before new Son()
    Parent initializer block
    Parent constructor
    Son initializer block
    Son constructor
    
    你必须知道这一点

  • 构造函数中的第一条指令是调用其父类的构造函数
    super(params)
    ,或者如果要使用默认构造函数
    super()
    。对于默认构造函数,您不必显式地编写它
  • 初始化程序块中的代码在
    super(…)
    调用之后立即移动到每个构造函数
  • 静态块在类初始化时执行,初始化是在JVM完全加载(及其父类)后完成的
  • 所以类被编译成与此类似的类

    public class Parent {
        static {
            System.out.println("Parent static block");
        }
    
        public Parent() {
            super();
            {
                System.out.println("Parent initializer block");
            }
            System.out.println("Parent constructor");
        }
    
    }
    
    public class Son extends Parent {
    
        static {
            System.out.println("Son static block");
        }
    
        public Son() {
            super();
            {
                System.out.println("Son initializer block");
            }
            System.out.println("Son constructor");
        }
    
        public static void main(String[] args) {
            new Son();
        }
    }
    
    为了能够从
    Son
    类执行
    main
    方法,JVM需要加载此类(及其扩展的类)的代码。类完全加载后,JVM初始化其静态内容,这涉及到执行静态块(是的,一个类中可以有多个静态块)。要完全加载
    Son
    类,JVM需要知道其父类的详细信息,以便在
    Son
    类之前完全加载
    parent
    类,这意味着它还将在
    Son
    类中的静态块之前执行其静态块

    因此,输出将如下所示:

    • 父静态块
    • 子静态块
    现在在
    main
    方法中,通过
    new-Son()
    调用
    Son
    类构造函数

    super();
    {
        System.out.println("Son initializer block");
    }
    System.out.println("Son constructor");
    
    因为它的
    super()
    引用了
    父类构造函数,它是

    super();// this will invoke Object constructor since Parent 
            // doesn't extend anything (which means it extends Object class)
    {
        System.out.println("Parent initializer block");
    }
    System.out.println("Parent constructor");
    
    结果你会看到

    • 父初始值设定项块
    • 父构造函数
    这将处理使用
    super()
    执行的
    Parent#constructor()
    ,因此接下来您将看到子构造函数在
    super()
    之后生成的代码