用Java手写jvm之实现java -version的效果

发布于:2024-07-27 ⋅ 阅读:(145) ⋅ 点赞:(0)

写在前面

源码
本文来用纯纯的Java代码来实现java -version的效果,就像下面这样:
在这里插入图片描述

1:程序

这里输出类似这样的:

java version "9"
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)

版本号信息比较简单,使用我们最拿手的sout就可以了,但是要获取用户设置的参数我们以我们现有的能力是做不到的,必须借助于外部力量了,也就是jar包:

<dependencies>
    <!-- 命令行参数解析器 -->
    <dependency>
        <groupId>com.beust</groupId>
        <artifactId>jcommander</artifactId>
        <version>1.72</version>
    </dependency>
</dependencies>

通过该类库我们可以很容易的获取到用户指定的命令行参数,接着解析命令行参数就可以给出用户想要的信息了:

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;

    String getMainClass() {
        return mainClassAndArgs != null && !mainClassAndArgs.isEmpty()
                ? mainClassAndArgs.get(0)
                : null;
    }

    List<String> getAppArgs() {
        return mainClassAndArgs != null && mainClassAndArgs.size() > 1
                ? mainClassAndArgs.subList(1, mainClassAndArgs.size())
                : null;
    }

    static Cmd parse(String[] argv) {
        Cmd args = new Cmd();
        JCommander cmd = JCommander.newBuilder().addObject(args).build();
        cmd.parse(argv);
        args.ok = true;
        return args;
    }

}

核心是注解com.beust.jcommander.Parameter,如果运行指定了某个参数则对应的布尔值就会被设置为true(如设置了-version 则versionFlag就会在解析后设置为true)。参数的解析工作通过方法static Cmd parse(String[] argv)完成,接着编写如下的测试类:

package com.dahuyou.write.jvm.version;

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 \"9(mine)\"\n" +
                    "Java(TM) SE Runtime Environment (build 9+181)\n" +
                    "Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)");
            return;
        }
        startJVM(cmd);
        System.out.println("xxxxxxxxxxxxx");
    }

    private static void startJVM(Cmd cmd) {
        System.out.printf("classpath:%s class:%s args:%s\n", cmd.classpath, cmd.getMainClass(), cmd.getAppArgs());
    }

}

编译:
在这里插入图片描述
接着运行(命令行方式):

E:\workspace-idea2019\waste-time-javaagent-and-javassist\target\classes>java -classpath D:\mvn_rep\mvn_rep_361\com\beust\jcommander\1.72\jcommander-1.72.jar;E:\workspace
-idea2019\write-jvm-self-query-java-version\target\classes com.dahuyou.write.jvm.version.Main -version
java version "9(mine)"
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)

这里要注意在-classpath中除了要指定依赖的jar外,还需要指定依赖的自己的class字节码文件(这个点卡了我好久/(ㄒoㄒ)/~~)。另外,这里的-classpath也可以简写为-cp

运行(idea方式):
在这里插入图片描述
在这里插入图片描述

写在后面

参考文章列表

java编译和运行带有包名的类


网站公告

今日签到

点亮在社区的每一天
去签到