使用 Java 8 的 javax.lang.model API (标准库)
这是 Java 官方提供的 API,主要用于注解处理 和在编译时进行代码分析,它不依赖于第三方库,是处理 Java 源代码的“标准”方式。

特点:
- 优点: 无需额外依赖,是 Java 标准库的一部分,稳定可靠。
- 缺点: API 相对底层和繁琐,功能有限,主要用于获取语法树结构,而不是进行深度语义分析。
- 适用场景: 编写注解处理器、简单的静态代码分析工具。
核心类:
javax.lang.model.element.Element:代码中的元素(包、类、方法、字段等)。javax.lang.model.util.Elements:工具类,用于操作Element。javax.lang.model.SourceVersion:定义支持的 Java 版本。
代码示例:
下面是一个简单的示例,它会解析一个 Java 文件,并打印出其中的所有顶级类、方法和字段。

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
import java.util.Set;
// 1. 定义注解处理器
@SupportedAnnotationTypes("*") // 处理所有注解
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class SimpleSourceFileParser extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// 获取工具类
Elements elementUtils = processingEnv.getElementUtils();
// 打印所有顶级类型(类、接口、枚举)
for (Element element : elementUtils.getPackageElements("").getEnclosedElements()) {
if (element.getKind().isClass() || element.getKind().isInterface() || element.getKind()isEnum()) {
System.out.println("Found Top-Level Element: " + element.getSimpleName());
printMembers(element);
}
}
return true;
}
private void printMembers(Element element) {
// 遍历元素内部的所有成员(方法、字段、嵌套类等)
for (Element member : element.getEnclosedElements()) {
switch (member.getKind()) {
case METHOD:
System.out.println(" -> Method: " + member.getSimpleName());
break;
case FIELD:
System.out.println(" -> Field: " + member.getSimpleName());
break;
case CLASS:
case INTERFACE:
System.out.println(" -> Nested Class/Interface: " + member.getSimpleName());
printMembers(member); // 递归打印嵌套成员
break;
}
}
}
}
如何运行这个示例?
你不能直接运行这个类,它需要被 Java 编译器(javac)调用。
-
将上述代码保存为
SimpleSourceFileParser.java。 -
编译它:
javac -cp $(echo $JAVA_HOME/lib/tools.jar) SimpleSourceFileParser.java(Linux/macOS) 或javac -cp "%JAVA_HOME%\lib\tools.jar" SimpleSourceFileParser.java(Windows)。 -
创建一个要解析的 Java 文件,
Test.java:
(图片来源网络,侵删)package com.example; public class Test { private int id; public String name; public void testMethod() { System.out.println("Hello"); } class InnerClass { void innerMethod() {} } } -
运行
javac并调用你的处理器:javac -processor SimpleSourceFileParser Test.java
输出:
Found Top-Level Element: Test
-> Field: id
-> Field: name
-> Method: testMethod
-> Nested Class/Interface: InnerClass
-> Method: innerMethod
使用第三方库 (如 JavaParser)
这是目前最流行、功能最强大的方法。JavaParser 是一个专门为解析、分析和转换 Java 源代码而设计的开源库。
特点:
- 优点: API 友好,功能强大,支持 AST(抽象语法树)的深度遍历和修改,支持 Java 1.0 到最新版本。
- 缺点: 需要添加第三方依赖(Maven/Gradle)。
- 适用场景: 代码分析工具、代码生成器、代码格式化、重构工具、静态代码检查等。
核心概念:
- CompilationUnit (编译单元): 代表一个完整的 Java 文件(
.java)。 - TypeDeclaration (类型声明): 代表一个类、接口或枚举。
- BodyDeclaration (体声明): 代表类或接口内部的成员,如字段、方法、构造函数、内部类等。
- Expression / Statement (表达式/语句): 代表代码中的具体逻辑。
代码示例:
使用 Maven 添加依赖:
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-symbol-solver-core</artifactId>
<version>3.25.5</version> <!-- 请使用最新版本 -->
</dependency>
示例代码:
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.io.FileInputStream;
public class JavaParserExample {
public static void main(String[] args) throws Exception {
// 1. 解析 Java 文件
FileInputStream in = new FileInputStream("src/main/java/com/example/Test.java");
CompilationUnit cu = JavaParser.parse(in);
// 2. 创建一个访问者来遍历 AST
cu.accept(new MethodVisitor(), null);
}
/**
* 一个自定义的访问者,用于查找所有方法并打印它们内部的变量
*/
private static class MethodVisitor extends VoidVisitorAdapter<Void> {
@Override
public void visit(MethodDeclaration md, Void arg) {
// 访问每个方法时执行
System.out.println("Found method: " + md.getName());
// 查找方法体内的变量声明
md.getBody().ifPresent(body -> body.findAll(VariableDeclarator.class).forEach(v -> {
System.out.println(" -> Variable: " + v.getName());
}));
super.visit(md, arg); // 确保访问子节点
}
}
}
解析 Test.java 后的输出:
Found method: testMethod
Found method: innerMethod
-> Variable: innerMethod
(注意:这个访问者只查找方法体内部的变量,id 和 name 没有被打印出来,这展示了访问者模式的灵活性。)
使用第三方库 (如 Eclipse JDT Core)
Eclipse JDT Core 是 Eclipse IDE 中用于处理 Java 代码的核心引擎,它非常强大,提供了完整的 Java 语言模型,包括类型解析、绑定解析等,可以进行深度的语义分析。
特点:
- 优点: 功能极其强大,最接近 IDE 的分析能力,可以理解类型、方法调用、继承关系等。
- 缺点: API 非常复杂,学习曲线陡峭,依赖较大。
- 适用场景: 构建功能强大的 IDE 插件、代码分析工具、需要理解代码语义的场景。
代码示例: 使用 Maven 添加依赖:
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core</artifactId>
<version>3.32.0</version> <!-- 请使用最新版本 -->
</dependency>
import org.eclipse.jdt.core.dom.*;
import java.io.File;
import java.io.FileReader;
public class JdtExample {
public static void main(String[] args) throws Exception {
// 1. 创建 AST 解析器
ASTParser parser = ASTParser.newParser(AST.JLS13); // 使用 Java 13 语法
parser.setSource(new FileReader(new File("src/main/java/com/example/Test.java")));
parser.setResolveBindings(true); // 关键:启用绑定解析,可以理解类型
// 2. 解析并得到 AST
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
// 3. 创建一个访问者
cu.accept(new ASTVisitor() {
@Override
public boolean visit(MethodDeclaration node) {
System.out.println("Found method: " + node.getName());
// 可以获取方法的返回类型
System.out.println(" -> Return type: " + node.getReturnType());
// 可以获取参数
node.parameters().forEach(p -> System.out.println(" -> Parameter: " + p.getName()));
return super.visit(node);
}
}, null);
}
}
输出:
Found method: testMethod
-> Return type: void
Found method: innerMethod
-> Return type: void
总结与对比
| 特性 | javax.lang.model (标准库) |
JavaParser (第三方库) |
Eclipse JDT Core (第三方库) |
|---|---|---|---|
| 易用性 | 较低,API 底层 | 高,API 友好 | 极低,API 复杂 |
| 功能 | 基础,语法层面 | 强大,语法+部分语义 | 最强大,完整语义分析 |
| 依赖 | 无 | 需要 Maven/Gradle 依赖 | 需要 Maven/Gradle 依赖 |
| 性能 | 较快 | 较快 | 相对较慢 |
| 适用场景 | 注解处理、简单分析 | 通用代码分析、代码生成、转换 | IDE 插件、深度语义分析 |
如何选择?
- 如果你只是想进行简单的编译时分析,并且不想引入任何外部依赖 -> 使用
javax.lang.model。 - 如果你是个人开发者或中小型项目,需要快速实现代码分析、生成或转换功能 ->
JavaParser是你的不二之选,它的文档、社区和易用性都非常好。 - 如果你在构建一个类似 IDE 的复杂工具,需要理解代码的深层含义(这个方法调用了哪个父类的方法”) -> 并且你不怕陡峭的学习曲线,
Eclipse JDT Core是最强大的选择。
对于绝大多数应用场景,从 JavaParser 开始是最佳实践,它能在功能和易用性之间取得完美的平衡。
