前言
学习Java虚拟机时,你是否也在为光看“八股文”而不知其意而困扰,或者困扰于缺少Java语言相关的项目?本系列就用Java实现一个Java虚拟机。
关于自己手写JVM的例子有很多,Jre 中的 JVM 一般用 cpp 实现。本系列跟随张秀宏老师的书《自己动手写 Java 虚拟机》进行教程主线的思路,说是go语言翻译为Java语言的移植版也不为过。
虽然是一个套娃的项目,但确实也算个项目,而且还可以引导切入JVM八股文,针不戳。
代码目录
ZYX-demo-jvm-01
├── pom.xml
└── src
└── main
│ └── java
│ └── org.ZYX.demo.jvm
│ ├── Cmd.java
│ └── Main.java
└── test
└── java
└── org.ZYX.demo.test
└── HelloWorld.java
下面我们进行命令行工具的编写。
解析简单的参数
1、导入jcommander依赖
先创建Maven项目,在pom.xml中导入jcommander依赖,这个库用于解析参数。
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>1.72</version>
</dependency>
2、Cmd类
首先定义一个Cmd类来表示命令行选项和参数。
public class Cmd {
@Parameter(names = {"-?", "-help"}, description = "print help message", order = 3, help = true)
boolean helpFlag = false;
@Parameter(names = "-version", description = "print version and exit", order = 2)
boolean versionFlag = false;
@Parameter(names = {"-cp", "-classpath"}, description = "classpath", order = 1)
String classpath;
@Parameter(description = "main class and args")
List<String> mainClassAndArgs;
boolean ok;
其中@Parameter是jcommander提供的,names可以是一个数组,表示参数的形式,description表示参数的描述信息,order表示参数在这个信息中的位置。
这里定义了三种参数,-help和-version使用boolean类型接收,-cp采用String类型接收,表示这个参数后面跟classpath的值,是一个字符串。
mainClassAndArgs是一个List,用于存储java命令后面的所有字符串,包括参数和运行的主类名称,布尔值ok表示是否解析成功。
然后是解析,解析是Jcommander的固定写法,采用builder模式。
static Cmd parse(String[] argv) {
Cmd args = new Cmd();
JCommander cmd = JCommander.newBuilder().addObject(args).build();
cmd.parse(argv);
args.ok = true;
return args;
}
返回的就是一个构建好的命令行选项和参数的包装。
3、主类
主类Main是今后整个JVM启动的主要流程框架。
public class Main {
public static void main(String[] args) {
Cmd cmd = Cmd.parse(args);
if (!cmd.ok || cmd.helpFlag) {
System.out.println("Usage: <main class> [-options] class [args...]");
return;
}
if (cmd.versionFlag) {
System.out.println("java version \"1.8.0\"");
return;
}
startJVM(cmd);
}
private static void startJVM(Cmd cmd) {
System.out.printf("classpath:%s class:%s args:%s\n", cmd.classpath, cmd.getMainClass(), cmd.getAppArgs());
}
}
首先是根据JVM参数来提供一些服务,目前只支持输出帮助信息和输出版本信息,如果都不需要,就可以启动虚拟机加载主类了。鉴于当前没法加载主类,所以就输出一下classpath的信息。
当然,输出版本号也只能输出一下1.8版本。