解释字节码之前执行静态块。如何?

时间:2018-07-05 06:58:28

标签: java jvm

当我们说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) {

    }
}

1 个答案:

答案 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[])

“应用程序类”和“主类”是可以互换的。

请注意,此列表仅用于将这些事件置于正确的顺序。幕后发生的事件更多。显然,要要求应用程序类加载器加载名称指定的应用程序类,必须StringClassClassLoader已被加载和初始化,这也意味着它们超类Object甚至在此之前就已初始化。主线程的存在意味着类Thread的加载和初始化。所有这些类都在幕后使用其他类。

您可以使用-verbose:class选项运行应用程序,以查看在应用程序类之前已经加载了哪些类。