据说java中的静态块只在加载该类时运行一次。但它实际上是什么意思?JVM(Java虚拟机)在什么时候加载一个类?
是在调用该类中的主要方法时吗?是不是同一个类的所有超类在main方法开始执行的时候也被加载了?
考虑 A 扩展 B 和 B 扩展 C。都有静态块。如果 A 有 main 方法,那么静态块的执行顺序是什么?
据说java中的静态块只在加载该类时运行一次。但它实际上是什么意思?JVM(Java虚拟机)在什么时候加载一个类?
是在调用该类中的主要方法时吗?是不是同一个类的所有超类在main方法开始执行的时候也被加载了?
考虑 A 扩展 B 和 B 扩展 C。都有静态块。如果 A 有 main 方法,那么静态块的执行顺序是什么?
这在 JLS 的执行部分中进行了描述。即:
类的初始化包括执行其静态初始化程序和类中声明的静态字段的初始化程序。接口的初始化包括执行接口中声明的字段的初始化程序。
在一个类被初始化之前,它的直接超类必须被初始化,但是由该类实现的接口不需要被初始化。类似地,接口的超接口不需要在接口被初始化之前被初始化。
因此,在您的示例中,“最顶层”类 ( C
) 的静态块首先运行,然后是 的B
,然后是派生最多的。
有关加载类的所有步骤的详细说明,请参阅该文档。
(类在第一次被主动使用时被加载。)
我认为以下示例将解决您的所有问题:
在一个类被初始化之前,它的超类被初始化,如果它们之前没有被初始化的话。
因此,测试程序:
class Super {
static { System.out.print("Super "); }
}
class One {
static { System.out.print("One "); }
}
class Two extends Super {
static { System.out.print("Two "); }
}
class Test {
public static void main(String[] args) {
One o = null;
Two t = new Two();
System.out.println((Object)o == (Object)t);
}
}
印刷:
Super Two false
类 One 永远不会被初始化,因为它没有被主动使用,因此永远不会被链接到。类 Two 仅在其超类 Super 被初始化后才被初始化。
有关更多详细信息,请访问此链接
编辑详细信息:删除了令人困惑的行。
来自Java 语言规范:
类的初始化包括执行其静态初始化程序和类中声明的静态字段(类变量)的初始化程序。接口的初始化包括执行在那里声明的字段(常量)的初始化程序。
在一个类被初始化之前,它的超类必须被初始化,但是类实现的接口没有被初始化。类似地,接口的超接口在接口初始化之前不会被初始化。
Java 虚拟机规范中更详细地描述了该过程。