实现java虚拟机_go实现java虚拟机01

前段时间看了一本书,说的是用go语言实现java虚拟机,很有意思,于是就花了一段时间学习了一下go语言,虽然对go的底层理解不是很深,但是写代码还是可以的,就当做个读书笔记吧!

链接在这里,另外还有一本《go程序设计语言》,有需要的直接一起拿走,链接:https://pan.baidu.com/s/152ZX7cLf5IcOzUk1C_Q8JQ  提取码:3ktm

首先我们知道java能够跨平台的原因就是class字节码文件在不同的jvm中都可以运行,每个计算机都可以安装符合自己操作系统的jvm,然后class文件就可以通用了,而class文件被包装的形式有很多种,最常见的应该就是jar包,有兴趣的可以看看打开自己的jdk中随便的个jar包,里面其实就是一些class字节码文件;

我们就简单一点,我们自己把一个java源码文件手动打包成一个jar包,下面的注释已经很清楚了

//javac HelloWorld.java将一个java源码文件编译成class文件//java手动将class文件打成jar包命令:jar cvf hello.jar HelloWorld.class//执行java -classpath hello.jar HelloWorld,表示执行hello中的jar包中HelloWorld中的main方法

public classHelloWorld {public static voidmain(String[] args) {

System.out.println("Hello, world!");

}

}

打成jar包之后,我们现在手中的文件有两个,一个是HelloWorld.class字节码文件,一个是hello.jar文件(jar包其实就是一个压缩包),我们分别用两条命令执行这两个文件,不知道大家有没有看出来什么?

如果是字节码文件的话,就是直接用java xxx执行就行了;如果是jar包的形式,那么我们必须要指定jar包的全路径,以及jar包里面main方法所在的字节码文件,这样jvm才能找到入口,就会在jar包中找到该文件,然后运行;我们可以实现一下命令行的处理方式:

a4ce6eeca88ad5a0e114ad5704997b4f.png

不知道大家还记不记得查看jdk版本的命令,就是java -version;在go语言中,对这种命令行参数的处理有两种,一种是os.Args这个切片来处理,另外一种通过一个flag包,选用后者,flag包封装了很多操作;

main.go代码如下:

packagemainimport "fmt"func main() {//同一个包下,私有方法也可以调用,如果是不同包,那就需要把parseCmd函数首字母大写

cmd :=parseCmd()//例如java -version,那么此时在parseCmd函数中解析version的值位true,然后赋值给versionFlag,就打印版本号

ifcmd.versionFlag {

fmt.Println("version 1.0.0")//例如输入的是java -help或者是java -classpath hello.jar ,没有加后面的类名,那么就调用printUsage函数//打印提示信息

} else if cmd.helpFlag || cmd.class == ""{

printUsage()//当参数都输入正确,那么就调用startJVM函数启动jvm,这里暂时就打印一句话,将输入的命令各部分参数都打印出来

} else{

startJVM(cmd)

}

}

func startJVM(cmd*Cmd) {

fmt.Printf("classpath:%s class:%s args:%v\n", cmd.cpOption, cmd.class, cmd.args)

}

cmd.go文件内容:

packagemainimport("flag"

"fmt"

"os")//简单的定义一个结构体,这里保存命令行中输入的参数

type Cmd struct {

helpFlag bool

versionFlag bool

cpOption stringclassstring

args []string

}

func parseCmd()*Cmd {

cmd := &Cmd{}//这里的意思就是如果解析失败的话,就调用printUsage函数

flag.Usage =printUsage//解析命令行中输入,例如java -help,那么这里help就是true,然后把true赋值给cmd结构体中helpFlag保存起来//最后一个是默认信息

flag.BoolVar(&cmd.helpFlag, "help", false, "print help message")//例如java -version,那么version就是true,赋值给cmd中的versionFlag

flag.BoolVar(&cmd.versionFlag, "version", false, "print version and exit ")//例如java -classpath hello.jar HelloWorld,这里classpath就是hello.jar,然后赋值给cpOption保存起来

flag.StringVar(&cmd.cpOption, "classpath", "", "classpath")//上面是定义解析规则,调用Parse函数才是真正开始解析

flag.Parse()//解析成功的话,那就继续获取后面的参数,注意这里的args是一个切片类型的//例如java -classpath hello.jar HelloWorld arg1,arg2,这里的args[0]表示HelloWorld,args[1:]表示arg1和arg2,//就是传给main方法形参字符串数组的参数

args :=flag.Args()if len(args) > 0{

cmd.class = args[0]

cmd.args= args[1:]

}returncmd

}//这里传进去的参数,解析错误的话就显示第一个参数的提示信息

func printUsage() {

fmt.Printf("Usage:%s [-options] class [args]\n", os.Args[0])

}

其实很容易,然后我们可以测试一下,目录结构如下,其中main.go和cmd.go都在ch01中,我们进入到src目录下,打开终端,输入go install jvmgo\ch01,就会在workspace/bin下生成一个ch01.exe可执行文件;

dbcd276aa1d08be9339732e7002af473.png

7f44229303f3d55ff2d7d74d8bffaeba.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值