当我们说java Test
时,类加载器会将.class文件加载到方法区域中,并且如果将任何静态变量初始化为分配的对应值,则将执行静态块。
在Java执行中,代码必须由Java解释器解释。但是静态块如何在不解释的情况下执行?它仍然处于课程加载阶段,不是吗?
但是在大多数博客和视频中,他们说在类加载完成后,将创建一个新线程,该线程将查找main方法并开始执行它。一旦主要方法开始在我看到的所有博客中执行,解释器就会出现。
class Test {
static int x = 10;
static {
int y = 10;
System.out.println(x);
}
public static void main(String[] args) {
}
}
答案 0 :(得分:2)
解释器的存在是与描述程序行为无关的实现细节。原则上,可能有一个根本没有解释器的JVM,因为它可能只有一个编译器,该编译器在执行之前将所有字节代码转换为本机代码,并且仍然实现正确的行为。当前的桌面JVM和服务器JVM都以混合模式执行代码。
因此,博客和视频提到存在解释器作为执行代码的方式也无关紧要,代码的执行总是暗示存在执行代码的技术手段,例如解释器或编译器
实际行为已在The Java Language Specification, §12.4.1中指定:
§12.4.1。初始化何时发生
类或接口类型T将在以下任何一种首次出现之前立即初始化:
T
是一个类,并创建了T
的实例。- 调用由
static
声明的T
方法。- 分配了
static
声明的T
字段。- 使用了
static
声明的T
字段,该字段不是常量变量(§4.12.4)。¹T
是顶层类(§7.6)和assert
语句(§14.10)的词汇,嵌套在T
({{3 }})被执行。初始化一个类时,将初始化其超类(如果之前尚未初始化),以及声明任何默认方法(§8.1.3)的所有超接口(§8.1.5)(如果它们已初始化)尚未预先初始化)。接口的初始化本身不会导致其任何超级接口的初始化。
¹这最后一个项目符号已从较新的规范中删除
由于对main
方法的调用是对您的类声明的“ static
方法的调用,因此它意味着在调用之前 对该类进行了初始化。从上一节可以得出,如果包含main
方法的类具有未初始化的超类,则它们将在该类之前进行初始化。
对于标准Java启动器,事件的顺序为
static void main(String[])
“应用程序类”和“主类”是可以互换的。
请注意,此列表仅用于将这些事件置于正确的顺序。幕后发生的事件更多。显然,要要求应用程序类加载器加载名称指定的应用程序类,必须String
,Class
和ClassLoader
已被加载和初始化,这也意味着它们超类Object
甚至在此之前就已初始化。主线程的存在意味着类Thread
的加载和初始化。所有这些类都在幕后使用其他类。
您可以使用-verbose:class
选项运行应用程序,以查看在应用程序类之前已经加载了哪些类。