介绍
手写一个简单的Java虚拟机,参考了bugstack虫洞栈,声哥,《自己动手写Java虚拟机》,和JVM-Demo。
本系列文章尽可能按照保姆级呈现。
如果有任何问题和建议,请联系我。
环境
操作系统:Windows 10
IDE:IntelliJ IDEA 2019.1 x64
JDK:Java 11.0.8
项目管理工具:apache-maven-3.5.4 [下载]
配置环境
Java的安装网上很多教程,就不赘述了。
注意安装Maven时,解压好之后要修改系统路径。然后试试调用cmd的mvn -v命令,如果调用不出来,重启即可。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210705085949574.png)
注意Maven的版本要和IDEA匹配,Maven版本不要比IDEA版本高,否则报错就不好了。
可能遇到的问题
开始项目了,打开IDEA,创建一个Maven项目。
![在这里插入图片描述](https://img-blog.csdnimg.cn/2021070508461280.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Zpc2hlcmlzaA==,size_16,color_FFFFFF,t_70)
创建pom.xml文件,直接拉到下面把我的pom.xml复制过来,然后试试能不能import。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210705084412181.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Zpc2hlcmlzaA==,size_16,color_FFFFFF,t_70)
如果不能,先在IDEA中把Maven home改了试试,就改为你的Maven安装(解压)地址(maven-repo是自己创建的):
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210705084254733.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Zpc2hlcmlzaA==,size_16,color_FFFFFF,t_70)
如果报错,log中出现 IDEA 2019 Unable to get current time from Google’s servers,那么可以试试禁用android support 插件:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210705085020426.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Zpc2hlcmlzaA==,size_16,color_FFFFFF,t_70)
如果报错 异常:[ERROR] 不再支持源选项 1.5。请使用 1.6 或更高版本 ,可能是因为java版本声明不对,在pom.xml中已经添加了java版本属性就可以解决:
<!-- 添加属性:使用的java版本为java11 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>1.8</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
开始:命令行工具
simpleJVM-01
├── pom.xml
└── src
└── main
│ └── java
│ └── cn.zwy.simplejvm
│ ├── Cmd.java
│ └── Main.java
└── test
└── java
└── cn.zwy.test
└── HelloWorld.java
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.zwy</groupId>
<artifactId>simpleJVM-01</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 添加属性:使用的java版本为java11 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
<java.version>1.8</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<!-- 解析命令行参数 -->
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>1.78</version>
</dependency>
</dependencies>
</project>
Cmd.java
package cn.zwy.simplejvm;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import java.util.List;
/**
* @author weiyu_zeng
*
* Parameter函数参数:
* names 设置命令行参数,如-old
* required 设置此参数是否必须
* description 设置参数的描述
* order 设置帮助文档的顺序
* help 设置此参数是否为展示帮助文档或者辅助功能
*/
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;
// 返回mainClassAndArgs的Class(List<String>的第一个参数)
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;
}
// 解析函数:传入String[] argv,返回Cmd类
static Cmd parse(String[] argv) {
Cmd args = new Cmd();
JCommander cmd = JCommander.newBuilder().addObject(args).build();
cmd.parse(argv); // 调用JCommander中的parse函数解析
args.ok = true; // 将ok标志位置为true
return args;
}
}
Main.java
package cn.zwy.simplejvm;
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);
}
// %s链接后面的变量
// 分别打印classpath, getMainClass()返回值,和getAppArgs()返回值
private static void startJVM(Cmd cmd) {
System.out.printf("classpath:%s class:%s args:%s\n",
cmd.classpath,
cmd.getMainClass(),
cmd.getAppArgs());
}
}
HelloWorld.java
package cn.zwy.test;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("hello world");
}
}
执行
可以直接执行Main.java。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210705141932510.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Zpc2hlcmlzaA==,size_16,color_FFFFFF,t_70)
目前还啥也没有:
classpath:null class:null args:null
点Edit Configurations
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210705142022313.png)
添加program argument:-version,激活我们定义的boolean versionFlag:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210705142136949.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Zpc2hlcmlzaA==,size_16,color_FFFFFF,t_70)
可以得到输出:
java version "1.8.0"
添加program argument:-help,激活我们定义的boolean helpFlag:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210705142301932.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Zpc2hlcmlzaA==,size_16,color_FFFFFF,t_70)
可以得到输出:
Usage: <main class> [-options] class [args...]