导读:本期聚焦于小伙伴创作的《如何在Java中理解静态初始化块和实例初始化块》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何在Java中理解静态初始化块和实例初始化块》有用,将其分享出去将是对创作者最好的鼓励。

什么是初始化块

在Java类中,除了属性和方法之外,还有一类特殊的代码块,被称为初始化块。初始化块没有名字,也没有参数,按照是否用static修饰,分为静态初始化块和实例初始化块两种。它们的作用是在类加载或者对象创建时,执行一些固定的初始化逻辑,很多时候可以替代构造器中重复的代码,让结构更清晰。

如何在Java中理解静态初始化块和实例初始化块

静态初始化块详解

定义与语法

静态初始化块是用static关键字修饰的初始化块,它的语法格式非常简单,就是在类内部直接写一个被static修饰的代码块:

public class StaticBlockDemo {
    // 静态初始化块
    static {
        System.out.println("静态初始化块执行了");
    }
}

静态初始化块属于类级别的代码,不属于任何一个实例对象,它的执行时机和类加载过程绑定。

执行时机与次数

静态初始化块的执行发生在类被首次主动使用的时候,JVM加载类的过程中,在类初始化阶段会执行静态初始化块。根据Java类加载的机制,同一个类加载器下,一个类只会被加载一次,因此静态初始化块在整个程序运行期间,只会执行一次。

哪些情况属于类的主动使用呢?常见的有:创建类的实例、访问类的静态变量或者静态方法、反射调用类、初始化类的子类时父类还没初始化等。如果只是通过类名访问类的静态常量(final修饰的基本类型或字符串),且常量在编译期就能确定值,不会触发类加载,也就不会执行静态初始化块。

典型使用场景

  • 初始化类的静态变量,尤其是需要复杂逻辑计算的静态变量,比如读取配置文件初始化全局配置项。
  • 加载类所需的静态资源,比如加载数据库驱动、初始化日志组件等只需要做一次的操作。
  • 执行类级别的校验逻辑,比如检查运行环境是否满足要求。

实例初始化块详解

定义与语法

实例初始化块是没有static修饰的普通初始化块,语法上就是一个直接写在类内部的代码块,不需要任何修饰符:

public class InstanceBlockDemo {
    // 实例初始化块
    {
        System.out.println("实例初始化块执行了");
    }
}

实例初始化块属于对象级别的代码,每次创建类的实例时,都会被触发执行。

执行时机与次数

实例初始化块的执行发生在对象创建的过程中,在构造器执行之前。准确来说,编译器会把实例初始化块的代码,复制到每一个构造器的开头,不管你定义了多少个构造器,每个构造器都会包含实例初始化块的逻辑。因此每次通过new关键字创建对象的时候,实例初始化块都会执行一次,创建多少个对象就执行多少次。

典型使用场景

  • 多个构造器有公共的初始化逻辑,把这些公共逻辑放到实例初始化块中,可以避免在每个构造器里重复写相同的代码。
  • 初始化对象的实例变量,尤其是需要统一初始化规则的非静态属性。
  • 执行对象创建时必须做的校验或者预处理逻辑,只要创建对象就会执行,不需要依赖具体调用的构造器。

两者的执行顺序对比

要彻底理解静态初始化块和实例初始化块,最核心的就是搞清楚它们的执行顺序,我们通过一个包含父类和子类的示例来验证:

// 父类
class Parent {
    // 父类静态初始化块
    static {
        System.out.println("父类静态初始化块执行");
    }
    // 父类实例初始化块
    {
        System.out.println("父类实例初始化块执行");
    }
    // 父类构造器
    public Parent() {
        System.out.println("父类构造器执行");
    }
}

// 子类
class Child extends Parent {
    // 子类静态初始化块
    static {
        System.out.println("子类静态初始化块执行");
    }
    // 子类实例初始化块
    {
        System.out.println("子类实例初始化块执行");
    }
    // 子类构造器
    public Child() {
        System.out.println("子类构造器执行");
    }
}

// 测试类
public class InitOrderTest {
    public static void main(String[] args) {
        System.out.println("第一次创建子类对象:");
        Child c1 = new Child();
        System.out.println("\
第二次创建子类对象:");
        Child c2 = new Child();
    }
}

运行上面的代码,输出结果如下:

第一次创建子类对象:
父类静态初始化块执行
子类静态初始化块执行
父类实例初始化块执行
父类构造器执行
子类实例初始化块执行
子类构造器执行

第二次创建子类对象:
父类实例初始化块执行
父类构造器执行
子类实例初始化块执行
子类构造器执行

从结果可以总结出完整的执行顺序规则:

  1. 首次使用类时,先执行父类的静态初始化块,再执行子类的静态初始化块,且静态初始化块只执行一次。
  2. 每次创建对象时,先执行父类的实例初始化块,再执行父类的构造器。
  3. 然后执行当前类的实例初始化块,再执行当前类的构造器。
  4. 如果创建多个对象,静态初始化块不会再执行,只重复执行实例初始化块和构造器。

如何在Java中理解静态初始化块和实例初始化块

和构造器的区别与联系

很多初学者会把实例初始化块和构造器搞混,其实两者有明确的区别:

对比项实例初始化块构造器
修饰符可以有访问修饰符(public、private等)
参数不能定义参数可以定义参数
执行逻辑所有构造器共享,固定逻辑不同构造器可以有不同逻辑
调用方式不能主动调用,随对象创建自动执行可以通过new主动调用,也可以构造器之间互相调用

联系在于:编译器会把实例初始化块的代码,插入到每一个构造器的起始位置,所以实例初始化块的执行一定在构造器之前,相当于构造器执行的前置公共步骤。

使用注意事项

  • 静态初始化块不能访问实例变量和实例方法,因为静态初始化块执行时可能还没有创建任何实例对象,实例成员还不存在。
  • 实例初始化块可以访问静态变量和静态方法,也可以访问实例变量,但此时实例变量还没有被构造器初始化,只能访问默认值或者通过初始化块赋值后的值。
  • 如果一个类有多个静态初始化块或者多个实例初始化块,它们会按照在类中定义的顺序依次执行。
  • 不要在初始化块中写过于复杂的逻辑,否则会让代码可读性下降,尤其是多个初始化块嵌套的时候,排查问题会比较麻烦。
  • 静态初始化块如果抛出异常,会导致类初始化失败,后续所有对该类的主动使用都会抛出ExceptionInInitializerError,要提前做好异常处理。

总结

静态初始化块和实例初始化块是Java中用来做初始化逻辑的重要语法,核心区别体现在归属级别、执行时机和执行次数上:静态初始化块属于类,类加载时执行一次,适合做类级别的全局初始化;实例初始化块属于对象,每次创建对象都执行,适合放多个构造器的公共初始化逻辑。理清两者的执行顺序,尤其是结合继承场景下的执行规则,能帮你避免很多初始化相关的问题,写出更规范的Java代码。

Java静态初始化块实例初始化块初始化顺序类加载修改时间:2026-05-24 20:39:03

免责声明:已尽一切努力确保本网站所含信息的准确性。网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。