1 | public class HelloWorld { |
运行上面的java程序时,我们知道首先要启动java虚拟机,然后加载主类,最后调用主类的main方法。但是在加载HelloWorld类之前,首先要加载它的超类java.lang.Object,在调用main()函数之前,虚拟机要准备好参数数组,所以需要加载java.lang.String和java.lang.String[]类。把字符串打印到控制台还需要加载java.lang.System类,等等。。那么java虚拟机如何寻找这些类的呢?
类路径
类路径可以分为以下三种:
- 启动类路径(bootstrap classpath):启动类路径默认对应jre/lib目录,Java标准库位于该路径。
- 扩展类路径(extention classpath):扩展类路径默认对应jre/lib/ext目录,使用Java扩展机制的类位于该路径。
- 用户类路径(user classpath):我们自己实现的类,以及第三方类库则位于用户类路径。用户类路径的默认值是当前路径,也就是”.”,可以给java命令传递-classpath选项来指定。
准备工作
把ch01的目录结构复制一份改名ch02,在ch02的目录中创建一个classpath子目录。
1 | |-jvmgo |
修改cmd结构体,添加XjreOption字段
1 | type Cmd struct { |
parseCmd()函数也对应添加Xjre
1 | //命令解析 |
实现类路径
采用组合模式来实现类路径,把类路径当成一个大的整体,由启动类路径、扩展类路径和用户类路径三个小路径构成,三个小路径又分别由更小的路径构成。
首先定义一个Entry接口
1 | //获取系统分隔符,windows是;类UNIX系统是:号 |
Entry接口一共有四种实现,CompositeEntry,WildcardEntry,ZipEntry,DirEntry
DirEntry
DirEntry相对简单些,表示目录形式的类路径
1 | package classpath |
ZipEntry
ZipEntry表示ZIP或者JAR文件形式的类路径
1 | package classpath |
CompositeEntry
CompositeEntry表示有分隔符的类路径,CompositeEntry由更小的Entry组成,可以表示成[]Entry,go语言中则使用便利的slice
1 | package classpath |
WildcardEntry
WildcardEntry表示以*结尾的类路径,实际上也是CompositeEntry,因此就不再新定义类型类
1 | package classpath |
Entry
四种类路径都实现完之后,再来完善下Entry接口,添加Entry实例的构造方法。
1 | func newEntry(path string) Entry { |
实现Classpath
1 | package classpath |
测试代码
完善main.go中的startJVM
1 | //模拟启动jvm |
编译main.go,并测试-version
1 | $ go install jvmgo/ch02 |

