java 读入class文件内容_手写JAVA虚拟机(三)——搜索class文件并读出内容

查看手写JAVA虚拟机系列可以进我的博客园主页查看。

前面我们介绍了准备工作以及命令行的编写。既然我们的任务实现命令行中的java命令,同时我们知道java命令是将class文件(字节码)转换成机器码,那么我们现在的任务就是读出这个class文件里面的内容。

正文:

java虚拟机规范中是没有规定虚拟机该从哪里找类,也就是找class文件的,而oracle的是根据类路径,也就是classpath来搜索类的。搜索的优先级:启动类路径(bootstrap classpath)>扩展类路径(extension classpath)>用户类路径(user classpath)。

启动类路径(bootstrap classpath):默认为指定的jre\lib目录。

扩展类路径(extension classpath):默认为指定的jre\lib\ext目录。

c6e7500aefd9e513251067af1a7d8a86.png

看一下我们现在的工作目录结构(具体工作目录看我博客首页前面的文章)。

19d593583f6bdb3d9f6eb6e807bfe5e5.png

1bab929c6bb0dc6ff017fb5463d84e90.png

与前一章看起来还是有一些差别的,后面会一一介绍。

类路径的设计我们我们采用组合模式。类路径由启动类路径、扩展类路径和用户类路径组成,这三个路径又由更小的路径构成。

首先定义一个接口来表示类路径。在ch02\classpath目录下创建entry.go文件,在其中定义Entry接口:

package classpath

import"os"import"strings"

//存放路径分隔符

const pathListSeparator = string(os.PathListSeparator)//定义Entry接口

type Entry interface{

readClass(classNamestring)([]byte,Entry,error)//查找和加载class文件

String() string//类似于java中toString()函数

}//类似于java的构造函数,根据参数创建不同类型的Entry

func newEntry(path string)Entry{ifstrings.Contains(path, pathListSeparator) {returnnewCompositeEntry(path)

}if strings.HasSuffix(path, "*") {returnnewWildcardEntry(path)

}if strings.HasSuffix(path, ".jar") || strings.HasSuffix(path, ".JAR") ||strings.HasSuffix(path,".zip") || strings.HasSuffix(path, ".ZIP") {returnnewZipEntry(path)

}returnnewDirEntry(path)

}

由newEntry()方法可能会猜到我们对Entry接口有4个实现,分别是DirEntry、ZipEntry、CompositeEntry和WildcardEntry,因此我们在classpath文件夹下面分别建立四个go文件,如图:

597d23eed656e8963f2b472214849662.png

其实这4种实现的基本逻辑都是类似的,我们以DirEntry为例详细说明(也就是entry_dir.go文件):

package classpath

import"io/ioutil"import"path/filepath"type DirEntrystruct{

absDirstring //存放绝对路径

}//用path创建一个DirEntry实例并返回

func newDirEntry(path string) *DirEntry{//将path转换为绝对路径,如果出错则panic,无错则创建DirEntry实例并返回

absDir,err:=filepath.Abs(path)if err!=nil{

panic(err)

}return &DirEntry{absDir}

}//将指定class的内容读出

func (self *DirEntry) readClass(className string) ([]byte,Entry,error){//讲绝对路径和文件名拼接在一起,并使用ioutil包读取该指定文件内容,返回结果

fileName :=filepath.Join(self.absDir,className)

data,err:=ioutil.ReadFile(fileName)returndata,self,err

}

func (self*DirEntry) String() string{returnself.absDir

}

首先引入了两个包,io/ioutil之前介绍过,类似于C的输入输出流,path/filepath用于对路径进行处理。然后定义了DirEntry这个结构体,里面只有一个absDir字段,类型为string,这个字段是用来存储绝对路径的。

再往下是三个函数。第一个newDirEntry(path string) *DirEntry,由于go语言中没有像java那样自带构造函数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值