静态代码块(static block)在Java中属于类的一部分,它在类被加载到内存时执行。以下是关于静态代码块执行时机的详细解释:
在类加载时执行
类的首次加载阶段
当类被加载到 Java 虚拟机(JVM)中时,静态代码块会被执行,而且只执行一次。这是因为静态代码块是与类相关联的,而不是与类的实例相关联。例如,在以下代码中:
class MyClass {
static {
System.out.println("静态代码块被执行");
}
public MyClass() {
System.out.println("构造函数被执行");
}
}
public class Main {
public static void main(String[] args) {
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
}
}
当Main类的main方法被执行时,MyClass类会被加载到 JVM 中,此时静态代码块会首先执行,输出 “静态代码块被执行”,然后再执行构造函数。当创建第二个MyClass对象时,静态代码块不会再次执行,因为类已经被加载过了。
静态代码块的执行顺序
如果一个类中有多个静态代码块,它们会按照在类中出现的顺序依次执行。例如:
class MultipleStaticBlocks {
static {
System.out.println("第一个静态代码块");
}
static {
System.out.println("第二个静态代码块");
}
}
在这个类中,当类被加载时,“第一个静态代码块” 会先执行,然后是 “第二个静态代码块”。
特殊情况说明
继承关系中的类加载
在继承关系中,父类的静态代码块会在子类的静态代码块之前执行。因为子类的加载依赖于父类,当子类被加载时,父类也会被加载(如果父类还没有被加载的话)。例如:
class ParentClass {
static {
System.out.println("父类静态代码块");
}
}
class ChildClass extends ParentClass {
static {
System.out.println("子类静态代码块");
}
}
public class Main {
public static void main(String[] args) {
ChildClass child = new ChildClass();
}
}
当Main类的main方法中创建ChildClass的对象时,首先会加载ParentClass,执行父类的静态代码块,然后加载ChildClass,执行子类的静态代码块。
通过反射机制加载类
当使用 Java 的反射机制来加载类时,静态代码块也会在类被反射加载时执行。例如:
import java.lang.reflect.Constructor;
class ReflectedClass {
static {
System.out.println("反射类的静态代码块执行");
}
}
public class Main {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("ReflectedClass");
Constructor<?> constructor = clazz.getConstructor();
constructor.newInstance();
}
}
在这个例子中,通过反射机制加载ReflectedClass时,静态代码块会在Class.forName方法调用时执行。