静态代码块、非静态代码块、构造函数的执行顺序

本文探讨了Java中静态代码块、非静态代码块及构造函数的执行顺序,并通过两个实例展示了不同情况下这些组件的执行顺序变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前被面试问到父子类静态代码块、非静态代码块、构造函数
一直以来我我认为这三者的执行顺序是静态代码块、非静态代码块、构造函数。
网上搜了下也都是这么说的。
就像下面这段代码:

public class ExA {
static {
System.out.println("父类--静态代码块");
}

public ExA() {
System.out.println("父类--构造函数");
}

{
System.out.println("父类--非静态代码块");
}

public static void main(String[] args) {
new ExB();
}
}

class ExB extends ExA {
static {
System.out.println("子类--静态代码块");
}
{
System.out.println("子类--非静态代码块");
}

public ExB() {
System.out.println("子类--构造函数");
}
}

执行结果
=====
父类--静态代码块
子类--静态代码块
父类--非静态代码块
父类--构造函数
子类--非静态代码块
子类--构造函数

可是静态代码块真的会一定在非静态代码块之前执行吗?
下面这段代码

public class ExA {
private static ExA a = new ExA();
static {
System.out.println("父类--静态代码块");
}

public ExA() {
System.out.println("父类--构造函数");
}

{
System.out.println("父类--非静态代码块");
}

public static void main(String[] args) {
new ExB();
}
}

class ExB extends ExA {
private static ExB b = new ExB();
static {
System.out.println("子类--静态代码块");
}
{
System.out.println("子类--非静态代码块");
}

public ExB() {
System.out.println("子类--构造函数");
}
}

执行结果
=====
父类--非静态代码块
父类--构造函数
父类--静态代码块
父类--非静态代码块
父类--构造函数
子类--非静态代码块
子类--构造函数
子类--静态代码块
父类--非静态代码块
父类--构造函数
子类--非静态代码块
子类--构造函数
=====
可以发现非静态代码块并不是一定在静态代码块之后执行的。
我认为此时private static ExA a = new ExA()是静态变量。而java里面静态变量与静态代码块是按代码先后顺序执行。所以就导致非静态代码块在静态代码块之前执行。
<think>嗯,用户想了解Java中静态代码块执行顺序和初始化过程。好的,首先我得回忆一下相关知识。记得静态代码块在类加载的时候执行,而且只执行一次。对吧?那静态代码块之间的顺序是按照它们在代码中的书写顺序执行的。比如如果有两个静态代码块,先写的那个会先执行。 然后,静态代码块会在main函数之前执行,对吧?因为main函数是程序的入口,但类加载的过程其实在main执行之前就完成了。所以静态代码块会在类加载的时候执行,然后才执行main方法。例如用户给的示例代码里,静态代码块1和2会在main函数输出之前打印。 另外,用户提供的引用资料里提到,静态代码块优先于各种代码块构造函数,包括实例初始化块和构造方法。所以当一个类被实例化的时候,静态代码块已经执行过了,实例初始化块和构造方法会在之后执行。如果有父类的话,还需要考虑父类的静态代码块执行,然后是子类的静态代码块,接着是父类的实例初始化块和构造方法,最后是子类的实例初始化块和构造方法。这点需要确认是否正确。 还要注意静态代码块只能访问静态成员,不能访问实例变量或方法。比如在静态代码块里调用静态的方法或变量会导致编译错误。比如引用3中的示例,静态代码块中尝试访问静态的x变量就会出错,所以必须只能调用静态的y变量和getY方法。 现在需要把这些整理成一个清晰的步骤,可能还需要示例代码来说明执行顺序。用户可能需要知道静态代码块在类加载时的具体时机,以及它们如何影响程序的初始化过程。另外,相关问题部分需要生成几个相关的问题,比如与其他初始化块的执行顺序比较,或者如何利用静态代码块进行资源初始化等。 还要确保回答中使用正确的中文,避免术语错误。同时,按照用户的要求,行内数学表达式用$...$,不过这个问题可能不涉及数学公式,但如果有的话需要注意格式。独立公式用$$...$$,但同样可能不适用。LaTeX语法正确,但这里主要是代码块和文字描述。 总结一下,回答的结构应该包括:静态代码块的定义,执行顺序的规则(多个静态代码块顺序,父类与子类的顺序,与main函数的关系),在初始化中的作用,示例代码,以及可能的相关问题。需要引用提供的参考资料来支持回答,比如引用1和引用2中的内容,说明静态代码块在main之前执行,以及多个静态代码块顺序。 可能还需要检查是否遗漏了其他重要点,比如静态代码块在类第一次被主动使用时触发,比如创建实例、访问静态方法或变量等。这时候类才会被加载,静态代码块才会执行。例如,如果只是声明一个类的引用而没有实际使用,静态代码块不会执行。这点是否需要在回答中提到呢?用户的问题是关于执行顺序和初始化过程,所以可能有必要提到类加载的触发条件。 总之,回答需要覆盖以下几点: 1. 静态代码块的定义和作用。 2. 执行顺序的规则(多个静态块、继承中的顺序)。 3. 与main函数和其他初始化块的执行顺序。 4. 示例代码及解释。 5. 静态代码块的使用场景和注意事项。 6. 引用中的相关内容支持这些点。 然后生成相关问题,比如与实例初始化块的比较,继承中的执行顺序,或者实际应用中的使用场景。</think>### Java静态代码块执行顺序与初始化过程解析 #### 一、静态代码块的核心特性 1. **执行时机** 静态代码块在**类加载阶段**执行,且**仅执行一次**,优先于实例初始化块、构造方法和`main`函数[^2]。 例如,在类首次被主动使用时(如创建实例、调用静态方法或访问静态字段),JVM会触发类加载。 2. **执行顺序规则** - **同一类中**:多个静态代码块按**代码书写顺序**依次执行。 - **继承关系中**:父类静态代码块 → 子类静态代码块 → 父类实例初始化块/构造方法 → 子类实例初始化块/构造方法[^2]。 --- #### 二、执行顺序示例 ```java class Parent { static { System.out.println("父类静态代码块"); } { System.out.println("父类实例初始化块"); } Parent() { System.out.println("父类构造方法"); } } class Child extends Parent { static { System.out.println("子类静态代码块1"); } static { System.out.println("子类静态代码块2"); } { System.out.println("子类实例初始化块"); } Child() { System.out.println("子类构造方法"); } public static void main(String[] args) { System.out.println("Main函数开始"); new Child(); System.out.println("Main函数结束"); } } ``` **输出结果**: ``` 父类静态代码块 子类静态代码块1 子类静态代码块2 Main函数开始 父类实例初始化块 父类构造方法 子类实例初始化块 子类构造方法 Main函数结束 ``` **关键过程**: 1. 类加载阶段执行父类和子类的静态代码块。 2. `main`函数作为入口,在静态代码块执行。 3. 对象实例化时,按继承链顺序执行实例初始化块和构造方法。 --- #### 三、静态代码块的作用 1. **初始化静态资源** 常用于加载配置文件、初始化静态变量等一次性操作。 例如: ```java class DatabaseConfig { static String URL; static { URL = "jdbc:mysql://localhost:3306/mydb"; System.out.println("数据库配置已加载"); } } ``` 2. **强制类加载** 通过静态代码块确保类在使用前完成初始化[^3]。 --- #### 四、注意事项 1. **静态代码块只能访问静态成员**,尝试访问实例变量或方法会导致编译错误[^3]。 2. 若类未被主动使用,静态代码块不会执行。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值