静态块vs初始化块与继承中的构造函数

时间:2014-02-01 22:52:57

标签: 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.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

4 个答案:

答案 0 :(得分:11)

你需要知道

  1. 构造函数中的第一条指令是调用其父类super(params)的构造函数,或者是否要使用默认构造函数super()。如果是默认构造函数,则不必显式编写它。
  2. 初始化程序块中的
  3. 代码在super(...)调用
  4. 之后立即移动到每个构造函数
  5. 在初始化类时执行静态块,这是在JVM完全加载(使用其父类)之后完成的。
  6. 因此,类被编译成类似于此的类。

    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();
        }
    }
    

    为了能够从main类执行Son方法,JVM需要加载此类的代码(以及它扩展的类)。在类完全加载后,JVM 初始化其静态内容,涉及执行静态块(是的,一个类中可能有多个静态块)。要完全加载Son类,JVM需要知道其父类的详细信息,以便它在Parent之前完全加载Son类,这意味着它还将在{{{}}中的静态块之前执行其静态块。 1}}类。

    因此输出如下:

    • Son
    • Parent static block

    现在在Son static block方法中,您通过main调用Son类构造函数,代码类似于

    new Son()

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

    Parent

    结果你会看到

    • 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");
    • Parent initializer block

    这会处理Parent constructor执行的Parent#constructor(),接下来您会看到super()生成后的Son构造函数的代码

    • super()
    • Son initializer block

    要在使用Son constructor构造函数甚至Son方法之前看到要加载的类,您可以在使用main构造函数之前打印一些内容,例如

    Son

    将导致

    System.out.println("ABC                      // before new Son()");
    new Son();
    

答案 1 :(得分:9)

当JVM加载并初始化类时,会调用一次静态块。在构造类的实例时执行实例初始化程序,就像构造函数一样。

Java Language Specification

中描述了静态和实例初始值设定项

答案 2 :(得分:2)

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

然后你创建对象所以你的父init块被调用然后你的父构造函数由于java中的构造函数链接然后派生类init块然后派生类构造函数

答案 3 :(得分:1)

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

静态初始值设定项相当于静态上下文中的构造函数。你肯定会比实例初始化器看到更多。