前言

学习Java虚拟机时,你是否也在为光看“八股文”而不知其意而困扰,或者困扰于缺少Java语言相关的项目?本系列就用Java实现一个Java虚拟机。

关于自己手写JVM的例子有很多,Jre 中的 JVM 一般用 cpp 实现。本系列跟随张秀宏老师的书《自己动手写 Java 虚拟机》进行教程主线的思路,说是go语言翻译为Java语言的移植版也不为过。

虽然是一个套娃的项目,但确实也算个项目,而且还可以引导切入JVM八股文,针不戳。


文章目录

  • 前言
  • 代码目录
  • 解析简单的参数
  • 1、导入jcommander依赖
  • 2、Cmd类
  • 3、主类


代码目录

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版本。