导读:本期聚焦于小伙伴创作的《什么是Java的代码块?静态代码块与构造代码块执行顺序如何理清》,敬请观看详情。类加载时静态代码块随类初始化仅执行一次,而构造代码块在每次创建对象时先于构造方法运行。不少初学者误以为二者执行时机相同,结果在统计实例数量或初始化配置时得到错误数据。理清顺序要先明确JVM加载机制:静态成员归属类,实例成员归属对象。当用new调用构造器,系统会先执行父类静态块、再本类静态块,随后父类构造块与构造器、本类构造块与构造器。借助断点调试和打印语句能直观看到输出次序,避免线上逻辑因初始化错位而异常。

在Java语言中,代码块是指用一对大括号包裹、没有名称和返回值的语句段,直接写在类体或方法体中。按照是否使用static修饰,最常见的两类是静态代码块和构造代码块。它们虽写法相似,却在生命周期与执行时机上完全不同,这也是很多人在写工具类或单例对象时容易踩坑的地方。

什么是Java的代码块?静态代码块与构造代码块执行顺序如何理清

一、Java代码块的基础概念

静态代码块使用static关键字修饰,格式为static { ... },它属于类级别的结构。当JVM第一次加载该类时,会执行静态代码块,且整个程序运行期间只执行这一次。通常我们会在这里做驱动注册、全局配置读取等只需一次的动作。

构造代码块则没有static,直接写{ ... },它属于对象级别。每当使用new创建该类实例时,构造代码块都会在构造方法主体之前被执行。也就是说,无论调用哪一个构造器,构造代码块中的逻辑都会先跑一遍,适合放多个构造器共享的初始化代码。

1.1 基础写法示例

下面这段代码展示了两种代码块的最简形式,以及它们在类里的位置:

public class Demo {
    // 静态代码块
    static {
        System.out.println("静态代码块执行");
    }

    // 构造代码块
    {
        System.out.println("构造代码块执行");
    }

    // 构造方法
    public Demo() {
        System.out.println("构造方法执行");
    }
}

从结构可以看到,静态块和构造块都独立于方法存在。它们不是方法,不能被显式调用,完全由虚拟机在类加载和对象实例化阶段自动触发。

二、静态代码块与构造代码块的执行顺序

要理清顺序,必须站在JVM视角看:类加载优先于对象创建。因此静态代码块一定早于任何构造代码块。而在同一个类的实例化过程中,构造代码块又早于构造方法。如果涉及继承,规则会再外扩一层。

具体次序为:父类静态块 → 子类静态块 → 父类构造块 → 父类构造器 → 子类构造块 → 子类构造器。这个链路保证了父类资源先就位,子类才能安全使用。很多框架的上下文初始化就是利用这一特性完成的。

2.1 单类场景下的顺序验证

我们用一段可运行程序观察无继承时的输出:

public class OrderTest {
    static {
        System.out.println("1. 静态代码块");
    }

    {
        System.out.println("2. 构造代码块");
    }

    public OrderTest() {
        System.out.println("3. 构造方法");
    }

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

运行后控制台会打印:第一次new时输出1、2、3;第二次new时只输出2、3。这证明静态块仅随类加载走一次,而构造块每次建对象都重跑。如果误以为静态块每次都执行,就会把计数或连接池初始化写错位置。

2.2 继承场景下的顺序验证

当存在父类时,顺序差异更明显,看下面例子:

class Parent {
    static { System.out.println("P 静态块"); }
    { System.out.println("P 构造块"); }
    Parent() { System.out.println("P 构造器"); }
}

class Child extends Parent {
    static { System.out.println("C 静态块"); }
    { System.out.println("C 构造块"); }
    Child() { System.out.println("C 构造器"); }
}

public class ExtTest {
    public static void main(String[] args) {
        new Child();
    }
}

输出依次是:P静态块、C静态块、P构造块、P构造器、C构造块、C构造器。可见静态部分先自上而下走完,再进入对象实例化链路。理解这一点,在写基类通用资源释放或子类专属配置时,就不会出现空指针或覆盖错误。

三、常见误区与正确使用建议

一个典型误区是把数据库驱动注册放进构造代码块,导致每次new对象都注册一次,轻则警告重则连接异常。正确做法是放在静态块,确保只注册一回。另一个误区是在构造块里依赖静态块中尚未赋值的静态变量,虽然同类加载时静态块先跑,但若是复杂类间引用仍可能踩到时序盲区。

建议把只需一次的、与实例无关的逻辑全放静态块;把每个对象都需要的字段预设或校验放构造块;构造方法只写特定于该重载的参数处理。配合日志打印或IDE断点,能快速确认执行流。这样分层后,代码可维护性会明显提升,也不会再被执行顺序搞混。

3.1 小结对照表

类型修饰符执行时机执行次数
静态代码块static类加载时1次
构造代码块对象创建、构造器前每实例1次

通过上表可以直观区分二者。实际开发中,只要牢记类优先于对象、静态优先于实例这条主线,静态代码块与构造代码块的执行顺序就不再难以判断。

Java代码块静态代码块构造代码块修改时间:2026-08-03 09:15:34

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