3.从0开始的手写java虚拟机 - 类加载过程实现
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
//MyObject.class
public class MyObject {
public static int staticVar;
public int instanceVar = 1;
public MyObject() {
}
public static void main(String[] args) {
int x = 12345;
MyObject myObj = new MyObject();
staticVar = x;
int x = staticVar;
if (myObj instanceof MyObject) {
myObj = (MyObject)myObj;
System.out.println(myObj.instanceVar);
System.out.println(myObj.instanceVar + staticVar);
}
}
}
//运行命令
//liyuan.exe -Xjre D:\jre1.8 -cp E:\m2\mysql\mysql-connector-java\8.0.21\mysql-connector-java-8.0.21.jar;E:\ideaProjects\HandWritingJVM\lib\*;E:\ideaProjects\HandWritingJVM MyObject
3.0.基础知识
3.1.运行时数据区
3.1.1.线程共享
堆:存放对象数据;
方法区:存放类数据,包括字段和方法信息,方法的字节码,运行时常量池…
3.1.2.线程私有
程序计数器:
Java虚拟机栈:栈帧,保存方法执行的状态,包括局部变量表,操作数栈;
3.1.类加载过程
- 解析类路径,启动类路径,扩展类路径,用户类路径
- 新建类加载器并加载主类,设置其基本信息,如父类,接口信息
- 校验该主类
- 准备:(1)计算实例的字段所需要的插槽数
- 准备:(2)计算静态字段所需的插槽数
- 准备:(3)初始化静态以及fianl变量
- 获取main方法
- 开始执行
func startJVM(cmd *Cmd) {
cp := classpath.Parse(cmd.XjreOption, cmd.cpOption)
classLoader := heap.NewClassLoader(cp)
fmt.Printf("classpath: %s class: %s args:%v\n", cmd.cpOption, cmd.class, cmd.args)
className := strings.Replace(cmd.class, ".", "/", -1)
mainClass := classLoader.LoadClass(className)
mainMethod := mainClass.GetMainMethod()
//classFile := loadClass(className, cp)
//fmt.Println(classFile)
if mainMethod != nil {
interpret(mainMethod)
} else {
fmt.Println("Main method could not be found in class %s\n", cmd.class)
}
}
3.1.1.解析类路径
见 1.从0开始的手写java虚拟机 - 读取类路径下的class文件
3.1.2.新建类加载器
//类加载器结构体
type ClassLoader struct {
cp *classpath.Classpath
classMap map[string]*Class //loaded class
}
func NewClassLoader(cp *classpath.Classpath) *ClassLoader {
return &ClassLoader{
cp: cp,
classMap: make(map[string]*Class),
}
}
//主要方法如下
//通过类名加载类
func (self *ClassLoader) LoadClass(name string) *Class {
//若该类已被加载过,则直接从内存取出
if class, ok := self.classMap[name]; ok {
//该类已被加载
return class
}
//否则从外存加载
return self.loadNonArrayClass(name)
}
//从类路径下加载主类
func (self *ClassLoader) loadNonArrayClass(name string) *Class {
//从路径下加载该类
data, entry := self.readClass(name)
class := self.defineClass(data)
link(class)
fmt.Printf("[Loaded %s from %s]\n", name, entry)
return class
}
func (self *ClassLoader) readClass(name string) ([]byte, classpath.Entry) {
data, entry, err := self.cp.ReadClass(name)
if err != nil {
panic("java.lang.ClassNotFoundException: " + name)
}
return data, entry
}
//解析成class格式
func (self *ClassLoader) defineClass(data []byte) *Class {
//将加载的文件解析成class格式
class := parseClass(data)
//设置类加载器
class.loader = self
//解析父类
resolveSuperClass(class)
//解析接口
resolveInterfaces(class)
//缓存下来
self.classMap[class.name] = class
return class
}
func parseClass(data []byte) *Class {
cf, err := classfile.Parse(data)
if err != nil {
panic("java.lang.ClassFormatError")
}
return newClass(cf)
}
//解析超类
func resolveSuperClass(class *Class) {
if class.name != "java/lang/Object" {
class.superClass = class.loader.LoadClass(class.superClassName)
}
}
//解析接口
func resolveInterfaces(class *Class) {
interfacesCount := len(class.interfaceNames)
if interfacesCount > 0 {
class.interfaces = make([]*Class, interfacesCount)
for index, name := range class.interfaceNames {
class.interfaces[index] = class.loader.LoadClass(name)
}
}
}
3.1.3.使用类加载器加载类并进行链接过程
//该方法同上
func (self *ClassLoader) LoadClass(name string) *