手写JAVA虚拟机(二)——实现java命令行
查看手写JAVA虚拟机系列可以进我的博客园主页查看。
我们知道,我们编译.java并运行.class文件时,需要一些java命令,如最简单的helloworld程序。
这里的程序最好不要加包名,因为加了包名的话编译和运行需要有所改动。
看这里的命令。javac为编译命令,我们知道java的特点是一次编译,到处运行。这里的编译指的就是javac,对于java程序即.java文件,先要用javac编译成字节码。然后将字节码(.class文件)放到java虚拟机中运行,即上图中的java HelloWorld,java虚拟机把字节码翻译成对应机器上的机器指令,再由机器来执行具体的机器指令。也就是说java程序员是直接与java虚拟机交互,简介与机器交互。所以虚拟机完成的是java命令,也就是我们要完成的是java这个指令的功能。
那么我们把第一个目标定为,实现简单的命令行。即我们通过命令行可以输入一些内容,虚拟机读取之后可以给一定的反馈。
GO语言中有两个和命令行相关的包,分别是os和flag(java中以类库即jar文件导入,go中直接以包的形式导入)。
首先在GOPATH目录下的src里面新建一个jvmgo文件夹作为我们的工作空间目录,jvmgo里面再新建一个ch01为我们的第一个目标源码文件夹,添加cmd.go文件。
在cmd.go里面输入如下代码(由于博客园的添加代码方式不支持go语言着色,所以采用C语言着色,高亮可能不太正确)
package main import "flag"
import "fmt"
import "os" //定义Cmd结构体
type Cmd struct{
helpFlag bool
versionFlag bool
cpOption string
class string
args []string
} //解析命令行参数
func parseCmd() *Cmd {
cmd:=&Cmd{} //将printUsage函数传给flag.Usage
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")
//所有选项设置完成后调用flag.Parse解析所有选项,如果Parse失败,则调用flag.Usage打印帮助信息
flag.Parse() //调用flag.Args函数捕获未被解析的参数,第一个参数为主类名,后面的为传递给主类的参数
args:=flag.Args()
if len(args)>{
cmd.class=args[]
cmd.args=args[:]
} return cmd
} func printUsage() {
fmt.Printf("Usage:%s[-options] class [args...]\n",os.Args[])
}
第一行为包名,main包,接着引入了三个包os,flag,fmt。os和flag都是处理命令行所需的包,fmt类似于C语言的printf和scanf等格式化IO。再往下定义了一个结构体Cmd,用来这个数据结构来格式化存储输入的命令行信息。helpFlag参数为命令行是否请求help,versionFlag参数为命令行是否请求version,cpOption为命令行传入的classpath即目标.class文件所在文件夹,class为命令行传入的.class文件名(不包括.class),args为命令行传入的其他参数。
紧接着是一个parseCmd函数(go语言有函数和方法之分,方法调用需要receiver,函数调用则不需要 ),返回值为*Cmd,用来解析cmd传过来的参数。该函数里面先声明一个cmd并给这个cmd赋值一个新建的Cmd对象。go语言中的“:=”为声明并赋值,而"="为赋值。先把printUsage的函数赋值给flag.Usage,然后调用flag设置需要解析的选项,全部解析完毕,调用Parse函数解析所有选项。解析成功则结束,解析失败则调用printUsage打印到控制台。
flag.Args可以捕获其他没有被解析的参数。上面解析成功之后,第一个参数就是主类名,剩下的就是传给主类的参数。
工具类编写完成,下一个是主函数。先上主函数代码:
package main import "fmt" func main() {
//调用parseCmd解析命令行参数
cmd:=parseCmd() if cmd.versionFlag{
//输入了-version选项
fmt.Println("version 0.0.1")
}else if cmd.helpFlag||cmd.class==""{
//输入了-help选项
printUsage()
}else{
//启动jvm
stratJVM(cmd)
}
} func stratJVM(cmd *Cmd){
fmt.Printf("classpath:%s class:%s args:%v\n",
cmd.cpOption,cmd.class,cmd.args)
}
跟java类似,在go里面main是一个特殊的包,go程序的入口就是main函数,但是不接受任何参数,也不能有返回值。main函数先调用parseCmd解析命令行参数,如果是-version则返回版本号,如果是-help则返回帮助信息,如果是其他则启动jvm,这里用一些输出信息“假装”启动了jvm,真正的jvm代码后面会加上。
至此,对命令行的解析工作全部完成。先展示一下整个工作目录的结构,不然后面编译运行的时候会出错。
我们的工作目录是D盘下的JVM里的goWorkSpace,再下面src,jvmgo,ch01,ch01里面包含的是我们的go文件。
来测试一下,打开一命令行,输入go install jvmgo\ch01。这个命令是使用go.exe来install文件,这个文件存在于GOPATH下面的文件夹(jvmgo\ch01中),结果如图:
然后在工作空间(GOPATH)的bin文件夹中就多出了一个ch01.exe。
在此处打开命令行。可以进行一些操作:
到这里,我们的命令行工具就完成了,虽然还没有涉及真正的虚拟机设计,但这也是虚拟机运行的重要一步,后面会逐渐介绍虚拟机的设计。
手写JAVA虚拟机(二)——实现java命令行的更多相关文章
- 深入理解Java虚拟机二之Java内存区域与内存溢出异常
运行时数据区域 1.线程独有的内存区域 PROGRAM COUNTER REGISTER 程序计数器 程序计数器空间较小,是当前线程执行字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值 ...
- 深入理解Java虚拟机(二)、Java对象的创建,内存布局和访问定位
对象的创建: Object obj = new Object(); 常量池中是否有Ljava.lang.Object
- 【java虚拟机序列】java中的垃圾回收与内存分配策略
在[java虚拟机系列]java虚拟机系列之JVM总述中我们已经详细讲解过java中的内存模型,了解了关于JVM中内存管理的基本知识,接下来本博客将带领大家了解java中的垃圾回收与内存分配策略. 垃 ...
- 转 Java虚拟机5:Java垃圾回收(GC)机制详解
转 Java虚拟机5:Java垃圾回收(GC)机制详解 Java虚拟机5:Java垃圾回收(GC)机制详解 哪些内存需要回收? 哪些内存需要回收是垃圾回收机制第一个要考虑的问题,所谓“要回收的垃圾”无 ...
- Java虚拟机如何运行Java字节码
一.Java的class文件的内容 1.首先编写一个简单的代码 public class StringDemo { public static void main(String[] args) { S ...
- 【Java虚拟机6】Java内存模型(Java篇)
什么是Java内存模型 <Java虚拟机规范>中曾试图定义一种"Java内存模型"(Java Memory Model,JMM)来屏蔽各种硬件和操作系统的内存访问差异, ...
- java虚拟机学习-触摸java常量池(13-1)
java虚拟机学习-深入理解JVM(1) java虚拟机学习-慢慢琢磨JVM(2) java虚拟机学习-慢慢琢磨JVM(2-1)ClassLoader的工作机制 java虚拟机学习-JVM内存管理:深 ...
- Java虚拟机2:Java内存区域
1.几个计算机的概念 为以后写文章考虑,也为巩固自己的知识和一些基本概念,这里要理清楚几个计算机中的概念. 1.计算机存储单位 从小到大依次为位Bit.字节Byte.千字节KB.兆M.千兆GB.TB, ...
- opencv 手写选择题阅卷 (二)字符识别
opencv 手写选择题阅卷 (二)字符识别 选择题基本上只需要识别ABCD和空五个内容,理论上应该识别率比较高的,识别代码参考了网上搜索的代码,因为参考的网址比较多,现在也弄不清是参考何处的代码了, ...
- <<深入Java虚拟机>>-第二章-Java内存区域-学习笔记
Java运行时内存区域 Java虚拟机在运行Java程序的时候会将它所管理的内存区域划分为多个不同的区域.每个区域都有自己的用途,创建以及销毁的时间.有的随着虚拟机的启动而存在,有的则是依赖用户线程来 ...
随机推荐
- Tomcat性能优化及JVM内存工作原理
Java性能优化原则:代码运算性能.内存回收.应用配置(影响Java程序主要原因是垃圾回收,下面会重点介绍这方面) 代码层优化:避免过多循环嵌套.调用和复杂逻辑. Tomcat调优主要内容如下: 1. ...
- bootstrap 之下拉多选
效果如图: 一.HTML代码 <label class="col-sm-1 control-label text-right" for="ds_host" ...
- win10 apache配置虚拟主机后localhost无法使用
win10系统配置虚拟主机1.用记事本或Sublime Text打开httpd.confctrl + f 搜索httpd-vhosts.conf 将#Include conf/extra/httpd- ...
- C# Post提交数据
/// <summary> /// Post提交数据 /// </summary> /// <param name="postUrl">URL& ...
- Spting +Spring MVC+spring date jsp +hibernate+jq
controller 控制页面跳转 处理前台后台数据交互 访问servicedao层:@Repository 数据库访问层 增删改查 jpa规范了hibernate jap仓库 jpa自动解析 方法名 ...
- 技巧:如何提升Oracle用户密码的安全性
环境:Oracle 11.2.0.4 客户需求:主要背景是数据库中有很多业务用户名,且由于部分用户缺乏安全意识,甚至直接将自己的密码设置为和用户名一样,目前客户期望密码设置不要过于简单,最起码别和用户 ...
- Java之GC
Java之GC GC:GC 是JVM的垃圾回收器.与C/C++不同,java程序员无需考虑太多内存分配的位置,更不用考虑内存释放的机制,java对象内存的申请和释放都有JVM托管.JVM的内存释放机制 ...
- 一日一练-CSS CSS中percentage百分值的使用
子曰:学好百分值,考试考百分 首先是确定CSS 中的percentage 都可以应用在CSS 中的哪些属性,以及这些属性的值如何进行计算的,参考CSS 参考手册进行统计. 定位(Positioning ...
- 解决IOS移动端 Safari流浪器 onclick无法触发的问题
在移动端布局的时候, 在底部有一个button, 页面超过两屏, 是一个可滚动的的网页, 当运行在移动端Safari浏览器上的时候, 向下滑动页面, 浏览器的头部和尾部会自动隐藏, 这样可视区域就会变 ...
- 医疗器械c#上位机开发指引教程
此教程面向的读者:对医疗器械上位机编程有兴趣,或者急需了解医疗器械(尿常规.血液分析.生化.心电.B超等医疗下位仪器)的编程流程.编程细节的程序员. 1.得到仪器协议 当我们需要与医疗器械等下位机数据 ...