java编译器将 java 源文件转换成 class 文件的过程。
(1)词法分析器
作用:将Java源文件的字符流转变成对应的Token流
每个词法单元(token)都有一个类型(token type)和一个值(token value)。例如:
**词法单元类型**可能包括:
- 关键字(如 `if`、`else`、`for`、`class` 等)
- 标识符(变量名或函数名)
- 运算符(如 `+`、`-`、`*`、`/`、`=` 等)
- 分隔符(括号、大括号 `{}`、方括号 `[]`、圆括号 `()`,以及逗号 `,`、冒号 `:`、分号 `;` 等)
- 字面量(整数、浮点数、字符串等)
- 注释
- 特殊符号(如EOF,表示文件结束)
**词法单元值**则是对应的文本内容。
举例说明:
假设有一个简单的Java源代码片段:
```java
int main() {
int x = 5;
if (x > 3) {
System.out.println("Hello, World!");
}
}
```
经过词法分析后,可能会产生如下形式的结果:
1. `(int, "int")`
2. `(identifier, "main")`
3. `(symbol, "(")`
4. `(symbol, ")")`
5. `(symbol, "{")`
6. `(int, "int")`
7. `(identifier, "x")`
8. `(symbol, "=")`
9. `(integer_literal, "5")`
10. `(symbol, ";")`
11. `(keyword, "if")`
12. `(symbol, "(")`
13. `(identifier, "x")`
14. `(symbol, ">")`
15. `(integer_literal, "3")`
16. `(symbol, ")")`
17. `(symbol, "{")`
18. `(identifier, "System")`
19. `(symbol, ".")`
20. `(identifier, "out")`
21. `(symbol, ".")`
22. `(identifier, "println")`
23. `(symbol, "(")`
24. `(string_literal, "\"Hello, World!\"")`
25. `(symbol, ")")`
26. `(symbol, ";")`
27. `(symbol, "}")`
28. `(symbol, "}")`
29. `(EOF, "")` (表示文件结束)
这里的每一组 `(类型, 值)` 就是词法分析器生成的一个个词法单元。这些单元后续会被传递给语法分析器进行进一步的语法结构分析。
(2)语法分析器
作用:将Token流组建成更加结构化的语法树
下面一个例子解析
public class HelloWorld {public static void main(String[] args) {System.out.println("Hello, World!");}
}
经过Java编译器的词法分析和语法分析后,得到的抽象语法树(AST)的大致结构可能是这样的:
CompilationUnit
└── ClassDeclaration
├── Modifier (public)
├── Identifier (HelloWorld)
├── ClassBody
│ └── MethodDeclaration
│ ├── Modifier (public)
│ ├── Modifier (static)
│ ├── Type (void)
│ ├── Identifier (main)
│ ├── FormalParameters
│ │ └── Parameter
│ │ ├── Type (String[])
│ │ └── Identifier (args)
│ └── MethodBody
│ └── StatementExpression
│ ├── MethodInvocation
│ │ ├── Name (System.out)
│ │ └── ArgumentList
│ │ └── StringLiteral ("Hello, World!")
│ └── SemiColon (;)
(3)插入式注解处理器
下篇专门写这个功能,
简介:插入式注解处理器可以帮助我们在javac编译期修改抽象语法树(AST),进而改变生成的class文件。
(4)语义分析器
1)检查语义的合法性并进行逻辑判断
如以下几点:
- 变量的类型是否匹配
- 变量在使用前是否已经完成初始化
- 能够推导出泛型方法的参数类型
- 字符串常量的合并
- 去掉无用的代码
- 变量的自动转换
- 去除语法糖
(5)代码生成器
代码生成器将注解语法树转化为字节码。
字节码生成是 javac 编译过程的最后一个阶段,将上面步骤所生成的注解语法树、符号表等信息转化成字节码指令写到 class 文件中。
(6)使用java代码调试(编译的过程)
1)javac命令可以编译源文件,
2)java代码类JavaCompiler也能编译源文件
java代码编译源文件的代码如下:
package com.dh.testJavac;import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;class TestJavac {/*** 默认找不到com.sun.tools.javac.processing.JavacProcessingEnvironment* 需要在idea->文件->项目结构->SDK->类路径->添加C:\Program Files\Java\jdk1.8.0_171\lib\tools.jar进去* @param args*/public static void main(String[] args) {JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
// com.sun.tools.javac.processing.JavacProcessingEnvironmentint r = systemJavaCompiler.run(null, null, null, "E:\\ideaWorkSpace\\shdhv3WorkSpace\\shdhv3\\src\\test\\java\\com\\dh\\testJavac\\ComClass.java");System.out.println(r==0?"成功":"失败");}}