当前位置: 首页 > 知识库问答 >
问题:

正常的init块在Java[duplicate]中到底什么时候执行

叶华皓
2023-03-14
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亚奥理事会考试。上面的代码来自我现在正在学习的书。根据答案,结果应该是

r1 r4 pre b1 b2 r3 r2 hawk

虽然我希望它是

pre r1 r4 b1 b2 r3 r2 hawk

考虑到这些规则:

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

谁能一步一步地告诉我这是怎么发生的吗?我可以理解r1r4在所有事情之前,但为什么pre就在它们之后?

共有2个答案

雍骏俊
2023-03-14

>

  • 构造函数中的第一条指令是调用其父类super(params)的构造函数。

    初始化器块中的代码在super()调用后执行。

    首先加载类hawk。由于它扩展了raptor,因此也加载了该类。当加载raptor时,它在其中执行静态块。

    因此得到r1r4

    在main方法执行之后。因此,o/p变为r1 r4 pre

    然后加载hawk。在调用hawk的构造函数时,调用raptor构造函数。raptor构造函数调用bird构造函数。这将加载bird类,并执行bird内的静态块,然后执行构造函数。

    因此O/P变为r1 r4 preb1 b2

    Bird's构造函数完成之后,执行r3块,并且Raptor构造函数完成。

    O/P变为r1 r4 pre b1 b2 r3 r2。

    最后执行最后一个sysout

  • 戴博
    2023-03-14

    当类Hawk加载时,类RaptorBird也必须加载,因为它们是超类,是Hawk定义的一部分。加载类时,将运行静态初始化器。“Static”实际上只是表示它是类的一部分,而不是类的实例。

    JVM要做的下一件事是开始执行main方法。它是静态的,所以还没有创建实例。这就是为什么接下来会打印“pre”。

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

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

    ps.在编写代码时,我会避免初始化器块。当所有语句都在构造函数方法中时,以后阅读代码和理解代码会更容易。一个例外是构建常量集合(即映射),因为Java实际上并不支持它(不像Python或JavaScript语法用于文字映射/指示/对象)。

     类似资料:
    • 自己写的service可以调basemapper也可以掉mybatis-plus中的service,有没有统一的规则?

    • 据我所知,init block是一个在任何构造函数之前执行的块,每当该构造函数用于创建对象时。但是为什么规则在这里矛盾...... 这里,由于只形成了子类对象,那么为什么要调用父类的init块呢?

    • 我在理解promise方面有一个(看似基本的)问题。首先是代码: 每个promise函数在添加到promise数组时被调用,而不是像我所想的那样调用Q.all。 我有什么不明白的? 如何在不立即调用所述promise的情况下将一系列promise排队?

    • 我正在学习Vue JS,发现有时我们导入{},有时我们导入时没有{}。请问有什么区别? 非常感谢。

    • (1)重载是多态的集中体现,在类中,要以统一的方式处理不同类型数据的时候,可以用重载。 (2)重写的使用是建立在继承关系上的,子类在继承父类的基础上,增加新的功能,可以用重写。 (3)简单总结: 重载是多样性,重写是增强剂; 目的是提高程序的多样性和健壮性,以适配不同场景使用时,使用重载进行扩展; 目的是在不修改原方法及源代码的基础上对方法进行扩展或增强时,使用重写; 生活例子: 你想吃一碗面,我

    • 我已经用Java编写代码一段时间了。但有时,我不知道什么时候应该抛出异常,什么时候应该捕获异常。我正在做一个有很多方法的项目。层次结构是这样的- 所以目前我正在做的是-我在所有方法中抛出异常并在方法A中捕获它,然后将其记录为错误。 但我不确定这是否是正确的方法?或者我应该开始在所有方法中捕获异常。这就是为什么这种混乱始于我的 - 我什么时候应该抓住异常与何时应该抛出异常。我知道这是一个愚蠢的问题,