在 Java 中,静态初始化块、静态变量、静态方法的赋值或执行时机与类加载密切相关。下面详细说明它们的赋值时机和执行顺序。
1. 静态变量的赋值时机
静态变量是属于类本身的变量,在类加载过程中完成初始化。赋值过程如下:
赋值阶段
-
默认初始化(类加载的准备阶段):
- JVM 为静态变量分配内存,并赋予默认值(如数字为
0
,布尔为false
,引用类型为null
)。 - 例如:
static int a; // 默认值为 0 static boolean b; // 默认值为 false
- JVM 为静态变量分配内存,并赋予默认值(如数字为
-
显式赋值(类加载的初始化阶段):
- 如果静态变量有初始值,类加载时会将显式赋值覆盖默认值。
- 例如:
static int a = 10; // 在类加载的初始化阶段,a 被赋值为 10
-
静态代码块中的赋值:
- 静态变量还可以在静态初始化块中被重新赋值。
- 静态代码块会按照代码中的顺序依次执行。
2. 静态初始化块的执行时机
静态初始化块在类加载的初始化阶段执行,用于对类进行额外的初始化操作。
执行特点
-
顺序执行:
- 如果有多个静态初始化块,按照它们在代码中的顺序依次执行。
- 静态初始化块会在所有静态变量完成显式赋值之后执行。
-
触发时机:
- 静态初始化块会在类加载时执行,并且只执行一次。
- 类加载的触发条件包括:
- 首次访问类的静态变量。
- 首次调用类的静态方法。
- 类实例化(通过构造方法)。
- 显式调用
Class.forName()
方法。
3. 静态方法的执行时机
静态方法是在类级别定义的,可以通过类名直接调用,而不需要实例化对象。
执行特点
-
加载类时不立即执行:
- 静态方法本身不会触发类的加载或初始化。
- 静态方法的执行取决于是否被显式调用。
- 调用时,类如果未加载,则先触发类加载。
-
调用时触发:
- 如果类未被加载,调用静态方法会导致类加载和静态初始化块的执行。
赋值或执行顺序
假设以下代码:
class Example {
static int a = 10; // 静态变量显式赋值
static int b; // 静态变量声明
static {
b = 20; // 静态代码块中为 b 赋值
System.out.println("Static block executed");
}
static void print() {
System.out.println("a = " + a + ", b = " + b);
}
}
public class Main {
public static void main(String[] args) {
Example.print(); // 触发静态方法
}
}
执行过程
-
类加载触发:
- 由于调用了
Example.print()
,类Example
被加载。
- 由于调用了
-
静态变量赋值:
a
被赋值为 10(显式赋值覆盖默认值)。b
默认值为 0,但静态代码块中将其赋值为 20。
-
静态初始化块执行:
- 静态代码块被执行,输出
"Static block executed"
。
- 静态代码块被执行,输出
-
静态方法执行:
- 调用
print()
方法,输出静态变量的值。
- 调用
输出结果:
Static block executed
a = 10, b = 20
总结:赋值时机和顺序
特性 | 赋值或执行时机 | 触发条件 |
---|---|---|
静态变量 | 默认初始化:类加载的准备阶段。 显式赋值:类加载的初始化阶段。 | 类首次加载时自动执行。 |
静态代码块 | 在类加载的初始化阶段,静态变量赋值完成后按顺序执行。 | 类首次加载时自动执行,只执行一次。 |
静态方法 | 只有在显式调用时才执行,调用时触发类加载(如果未加载)。 | 方法被调用时执行。如果类未加载,会触发类加载。 |
静态变量和静态初始化块共同决定类的初始状态,而静态方法则提供了类级别的行为,执行时可能触发类加载和静态初始化。