This question already has answers here:
Java order of Initialization and Instantiation
                                
                                    (2个答案)
                                
                        
                                4年前关闭。
            
                    
class Bird {
    {
        System.out.print("b1 ");
    }

    public Bird() {
        System.out.print("b2 ");
    }
}

class Raptor extends Bird {
    static {
        System.out.print("r1 ");
    }

    public Raptor() {
        System.out.print("r2 ");
    }

    {
        System.out.print("r3 ");
    }
    static {
        System.out.print("r4 ");
    }
}

class Hawk extends Raptor {
    public static void main(String[] args) {
        System.out.print("pre ");
        new Hawk();
        System.out.println("hawk ");
    }
}


我正在准备Java OCA考试。上面的代码摘自我正在研究的书。根据答案,结果应该是

r1 r4 pre b1 b2 r3 r2 hawk


虽然我希望它是

pre r1 r4 b1 b2 r3 r2 hawk


考虑以下规则:


静态初始化块在首次加载类时运行
正常的初始化块在所有超级构造函数运行后立即运行


有人可以一步一步告诉我这是怎么发生的吗?我可以理解r1r4排在一切之前,但是为什么pre在它们之后?

最佳答案

加载类Hawk时,还必须加载类RaptorBird,因为它们(作为超类)是Hawk定义的一部分。加载类后,将运行静态初始化程序。 “静态”实际上只是意味着它是类的一部分,而不是类的实例。

JVM的下一步是开始执行main方法。它是静态的,因此尚未创建任何实例。这就是为什么下一个打印“ pre”的原因。

然后main方法创建Hawk的实例,该实例将调用构造函数。在输入构造函数方法之前,将按文件中的顺序执行非静态初始化器块以及字段初始化(这些类没有任何初始化)。

之后,它会打印“鹰”并退出。



PS。在编写代码时,我避免使用初始化程序块。当所有语句都在构造方法中时,更容易阅读代码并在以后理解它。一个例外是构建常量集合(即Maps),因为Java否则实际上并不支持它(与文字映射/字典/对象的Python或JavaScript语法不同)。

10-05 19:13