侧边栏壁纸
博主头像
LYMTICS

海纳百川,有容乃大

  • 累计撰写 45 篇文章
  • 累计创建 37 个标签
  • 累计收到 19 条评论

目 录CONTENT

文章目录

自己动手写JVM(一)

LYMTICS
2022-01-24 / 0 评论 / 1 点赞 / 83 阅读 / 2,460 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-01-24,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

自己动手写JVM(一)

简介

本章主要是搭建了一个 java 命令的基本框架。

在 Go 语言中,可以用 flag官方文档)这个内置的包对命令行的参数进行处理,这样相比于读取 os.Args 再处理会简单。建议在编写前看一下上面提到的文档。

新增的结构

Cmd

这里用 Cmd 结构保存经过 flag 渲染后的命令行参数

type Cmd struct {
	helpFlag    bool     // 帮助
	versionFlag bool     // 版本
	cpOption    string   // ClassPath Options 类路径的参数
	class       string   // 类名
	args        []string // 保存命令的其他参数
}

代码

// ch01/main.go

package main

import "fmt"

// 编写了一个入门小框架
// 入口
func main() {
	// 创建一个Cmd实例,接收并处理命令行参数
	cmd := parseCmd()

	if cmd.versionFlag {
		fmt.Println("version 0.0.1")
	} else if cmd.helpFlag || cmd.class == "" {
		printUsage()
	} else {
		startJVM(cmd)
	}
}

func startJVM(cmd *Cmd) {
	fmt.Printf("classpath:%s class:%s args:%v\n",
		cmd.cpOption, cmd.class, cmd.args)
}
// ch01/cmd.go

package main

import (
	"flag" // 获取命令行参数的工具
	"fmt"  // 输出
	"os"   // 获取命令行参数
)

// Java 命令的调用格式: java [-options] class [args...]
// 用来保存处理后的命令行参数信息
type Cmd struct {
	helpFlag    bool     // 帮助
	versionFlag bool     // 版本
	cpOption    string   // ClassPath Options 类路径的参数
	class       string   // 类名
	args        []string // 保存命令的其他参数
}

// 构造函数模式,返回一个Cmd的实例
func parseCmd() *Cmd {
	cmd := &Cmd{}

	// flag.Usage: It is called when an error occurs while parsing flags.
	// 就是-h显示默认的帮助信息, 如果没有覆盖的话就打印下面声明的那些默认值
	// 这里覆盖了, 所以就输出自己编写的代码
	flag.Usage = printUsage

	// 保存的位置-命令-默认值-作用说明
	flag.BoolVar(&cmd.helpFlag, "help", false, "print help message")
	flag.BoolVar(&cmd.helpFlag, "?", false, "print help message")
	flag.BoolVar(&cmd.versionFlag, "version", false, "print version and exit")
	flag.StringVar(&cmd.cpOption, "classpath", "", "classpath")
	flag.StringVar(&cmd.cpOption, "cp", "", "classpath")
	// 调用Parse进行渲染
	flag.Parse()

	// 获取命令行参数
	// 这里如果命令后面的参数>0,就把第一个保存为类名,后面的保存在args里
	args := flag.Args()
	if len(args) > 0 {
		cmd.class = args[0]
		cmd.args = args[1:]
	}
	return cmd
}

// 输出错误信息,在发生异常时调用
func printUsage() {
	fmt.Printf("Usage: %s [-options] class [args...]\n", os.Args[0])
	//flag.PrintDefaults()
}

注意

注意VSCode插件的一键RUN可能不对,书中提到在当前目录用 go install 编译并生成结果,这样的话最终结果会保存在go的工作目录中,也可以用 go build ,这样生成的结果就在当前目录。

运行示例:

# 版本
$ .\ch01.exe -version
version 0.0.1

# 跟一个参数会被当做包名
$ .\ch01.exe java.lang.ArrayList
classpath: class:java.lang.ArrayList args:[]

# 其他的会被保存在args中
$ .\ch01.exe java.lang.ArrayList "a" "b"
classpath: class:java.lang.ArrayList args:[a b]

# 帮助信息
$ .\ch01.exe -?
Usage: D:\codingspace\Golang\gvm\ch01\ch01.exe [-options] class [args...]

# 什么也不输,也会输出帮助信息
$ .\ch01.exe
Usage: D:\codingspace\Golang\gvm\ch01\ch01.exe [-options] class [args...]

# 输入没有的参数
$ .\ch01.exe -x
flag provided but not defined: -x
Usage: D:\codingspace\Golang\gvm\ch01\ch01.exe [-options] class [args...]
1

评论区