Java程序编译过程

Java编译过程

一般,C/C++程序的编译过程可以分为5个步骤(见下图):Preprocessing(预处理),Parsing(解析), Translation(翻译),Assembling(汇编),Linking(链接)。

Java程序具有平台无关性,其在Java Virtual Machine(JVM)上执行,因此编译过程与C/C++大不相同:Java程序首先由编译器翻译成包含了Bytecode(字节码)的.class文件,程序执行时,由类加载器(class loader)将该类的字节码加载到JVM中,JVM会解释执行相应的Bytecode。

那么,一个Java程序是如何变成Bytecode的了?主要由3个过程:

(1) 解析:Java源代码文件被解析成一个个标记(Token),解析器根据Token生成语法树(syntax trees);
(2) 注释处理:注释处理器(annotation processors)处理所有注释;如果注释处理器产生了新的源文件或者class文件,会重启编译过程,直到没有新的文件产生为止;
(3) 语义分析与字节码生成:在这一步,将语法树转化成类文件,生成字节码。

  • 变量/引用等变量或符号标注;
  • 数据与控制流分析:局部变量赋值、方法返回值以及异常处理等逻辑验证;
  • 解析语法糖:如泛型与类型擦除,遍历循环、自动拆箱(装箱)以及条件编译等
  • 产生字节码,输出到磁盘

Java字节码

最后,我们来看一看Java字节码究竟长什么样子。

新建一个.java文件,

1
2
3
4
5
6
7
public class HelloWorld{
private static final String helloWorld = "hello world";

public static void main(String[] args){
System.out.println(helloWorld);
}
}

利用javac编译生成对应的.class文件,输入下列命令

1
javap -c xxx.class 

可以反汇编对应class文件的字节码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

//Compiled from "HelloWorld.java"

public class HelloWorld {
public HelloWorld();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String hello world
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}

这里,bytecode实际上就成了JVM的机器语言,里边是一条条JVM可执行的指令。

参考文献