java的static块执行时机

Java静态块执行时机揭秘
本文详细解析了Java中静态块(static block)的执行时机,解释了其在类初始化阶段的作用,并通过具体示例说明了类加载、连接与初始化的过程。了解static块何时运行对于深入理解JVM工作原理至关重要。

之前一直认为static块是在class load的时候执行,今天在验证Spring初始化Context loader的时候,发现bean的static块并没有执行。

Class A{   
    static{
       System.out.println("static block invoked!")
    }
 }

那么static块到底在什么时候运行的呢?如果了解JVM原理,我们知道,一个类的运行分为以下步骤:

  1. 装载
  2. 连接
  3. 初始化

其中装载阶段又三个基本动作组成:

  1.     通过类型的完全限定名,产生一个代表该类型的二进制数据流
  2.     解析这个二进制数据流为方法区内的内部数据结构
  3.     创建一个表示该类型的java.lang.Class类的实例

 另外如果一个类装载器在预先装载的时遇到缺失或错误的class文件,它需要等到程序首次主动使用该类时才报告错误。

 连接阶段又分为三部分:

  1. 验证,确认类型符合Java语言的语义,检查各个类之间的二进制兼容性(比如final的类不用拥有子类等),另外还需要进行符号引用的验证。
  2. 准备,Java虚拟机为类变量分配内存,设置默认初始值。
  3. 解析(可选的) ,在类型的常量池中寻找类,接口,字段和方法的符号引用,把这些符号引用替换成直接引用的过程。

当一个类被主动使用时,Java虚拟就会对其初始化,如下六种情况为主动使用:

  1. 当创建某个类的新实例时(如通过new或者反射,克隆,反序列化等)
  2. 当调用某个类的静态方法时
  3. 当使用某个类或接口的静态字段时
  4. 当调用Java API中的某些反射方法时,比如类Class中的方法,或者java.lang.reflect中的类的方法时
  5. 当初始化某个子类时
  6. 当虚拟机启动某个被标明为启动类的类(即包含main方法的那个类)

  Java编译器会收集所有的类变量初始化语句和类型的静态初始化器,将这些放到一个特殊的方法中:clinit。

实际上,static块的执行发生在“初始化”的阶段。初始化阶段,jvm主要完成对静态变量的初始化,静态块执行等工作。

 

下面我们看看执行static块的几种情况:

1、第一次new A()的过程会打印"";因为这个过程包括了初始化

2、第一次Class.forName("A")的过程会打印"";因为这个过程相当于Class.forName("A",true,this.getClass().getClassLoader());

3、第一次Class.forName("A",false,this.getClass().getClassLoader())的过程则不会打印""。因为false指明了装载类的过程中,不进行初始化。不初始化则不会执行static块。

参考资料:深入Java虚拟机

<think>首先,用户的问题是:“我想理解Java类中static代码、静态变量和静态方法的执行顺序请问javastatic代码静态变量静态方法执行顺序”。这是一个关于Java中静态元素执行顺序的查询。根据系统级指令:-所有行内数学表达式必须使用$...$格式,但这个问题是关于Java的,没有数学表达式,所以可能不需要。-独立公式必须使用$$...$$格式,但同样,这里没有公式。- LaTeX语法正确,但Java代码不需要LaTeX。 -使用中文回答。 -生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如[^1]。用户可见层指令: -回答结构清晰,帮助用户逐步解决问题。-尽量保证回答真实可靠。-参考站内引用:提供了三个引用,但用户说“上述引用仅供参考,并不是用户真正的需求”,所以我需要基于Java知识回答,而不是直接引用这些内容。参考引用内容: -[^1]讨论了static执行顺序,包括静态变量和静态代码。- [^2]详细解释了static静态变量、方法、代码的作用和初始化顺序。 -[^3]给出了一个例子,说明静态代码、静态变量、成员变量等的执行顺序。 关键点从引用中提取: -static修饰的元素在类加载时初始化。-静态变量和静态代码的初始化顺序按照它们在代码中的顺序。 -静态内容优先于非静态内容。-在类加载时,静态代码和静态变量初始化,然后才是对象创建时的成员变量和构造方法。用户的问题聚焦在:static代码、静态变量和静态方法的执行顺序。注意,静态方法本身不是初始化的一部分;静态方法在调用时执行,但初始化是关于静态变量和代码的。执行顺序:1.当类首次被加载时(例如,第一次访问类时),所有static元素初始化。 2.初始化顺序:静态变量和静态代码按照它们在代码中出现的顺序执行。3.静态方法在调用时执行,不涉及初始化顺序;它们只是方法。所以,顺序是:-静态变量初始化(赋值)。-静态代码执行。 它们按声明顺序执行。 例如,在代码中: ```javapublic classExample{static inta =10; //静态变量初始化static {System.out.println("Staticblock1");//静态代码}staticint b=20;static{System.out.println("Static block2");} }``` 加载类时,顺序是:- a初始化(10)-第一个静态代码执行- b初始化(20) -第二个静态代码执行静态方法,如publicstatic voidmyMethod(),在调用时执行,比如Example.myMethod(),不参与初始化顺序。 回答结构:1.解释static元素的初始化时机:类加载时。2.描述执行顺序:静态变量和静态代码按代码顺序执行。 3.强调静态方法在调用时执行。4.提供简单代码示例。5.生成相关问题。使用中文。生成相关问题: 基于主题,可以问:1.静态元素和非静态元素的执行顺序差异? 2.如何优化静态初始化? 3.静态代码的使用场景?4.在继承中的执行顺序?引用标识:如果引用参考内容,但用户说“请尽可能多的参考用户上一次的问题和你的回答”,但这是第一次交互,所以基于知识回答。如果需要,可以自然添加引用,但引用是站内的,可能不直接相关。 最终回答大纲: -介绍:静态元素在类加载时初始化。 -详细顺序:静态变量和静态代码按声明顺序执行。-示例代码。 -静态方法说明。 -相关问题。</think>### Javastatic代码、静态变量和静态方法的执行顺序 在Java中,`static`修饰的元素(包括静态代码、静态变量和静态方法)在类加载阶段初始化,而非对象创建阶段。执行顺序遵循严格的规则,确保静态内容优先初始化。以下是详细解释: #### 1. **初始化时机** - 当类首次被加载时(例如,首次访问类的静态成员或创建对象),JVM会初始化所有`static`元素。 - 静态内容仅初始化一次,且优先于非静态内容(如成员变量或构造方法)[^2][^3]。 #### 2. **执行顺序规则** - **静态变量和静态代码按声明顺序执行**:在类加载时,静态变量赋值和静态代码按照它们在代码中出现的顺序依次执行。 - 例如: ```java public class Example { static int a = initA(); // 静态变量1 static { System.out.println("静态代码1"); // 静态代码1 } static int b = 20; // 静态变量2 static { System.out.println("静态代码2"); // 静态代码2 } private static int initA() { System.out.println("初始化a"); return 10; } } ``` 加载类时,顺序为: 1. `a`初始化(调用`initA()`)。 2. 执行第一个静态代码。 3. `b`初始化。 4. 执行第二个静态代码。 - **静态方法不参与初始化顺序**:静态方法(如`public static void myMethod()`)仅在调用时执行,与类加载无关。例如,`Example.myMethod()`会在需要时运行,不影响静态变量或代码的初始化[^2]。 #### 3. **关键原则** - **静态优先于非静态**:所有静态元素初始化完成后,才会处理成员变量、构造代码或构造方法。 - **顺序依赖代码位置**:如果静态变量和静态代码交错声明,JVM严格按代码顺序执行。 - **继承中的顺序**:在子类加载时,先初始化父类的静态内容,再初始化子类的静态内容[^3]。 #### 4. **示例验证** 运行以下代码: ```java public class Test { static { System.out.println("静态代码执行"); } static int var = initVar(); private static int initVar() { System.out.println("静态变量初始化"); return 5; } public static void main(String[] args) { System.out.println("main方法执行"); } } ``` 输出: ``` 静态代码执行 静态变量初始化 main方法执行 ``` 说明:静态代码和静态变量按顺序执行,`main`方法(静态方法)在类加载后调用。 #### 5. **注意事项** - 静态代码常用于一次性初始化静态变量或资源(如数据库连接)[^2]。 - 静态方法不能直接访问非静态成员,因为非静态内容尚未初始化[^2]。 - 如果多个类依赖,加载顺序遵循类引用关系,但每个类内部的静态顺序不变[^3]。 通过理解这些规则,您可以避免初始化顺序导致的错误,如空指针异常[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值