跳至主要內容

10、类加载器

引领潮流大约 2 分钟手动编写jvm虚拟机jvmgo

知识扩展

  • 1、依赖classpath 读取class文件
  • 2、map存储class类
  • 3、动态加载class

1、定义classloader

type ClassLoader struct {
	cp       *classpath.Classpath // 用于搜索和读取 class 文件
	classMap map[string]*Class    // 已经加载的类数据,key=全限定类名
}

// 创建一个类加载器
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) // 普通类的数据来自于class文件,数组类的数据是jvm在运行期间动态生成的
}

2、类加载过程

// 类加载过程
func (self *ClassLoader) loadNonArrayClass(name string) *Class {
	data, entry := self.readClass(name) // 1. 找到class文件并读取为 byte[]
	class := self.defineClass(data)     // 2. byte[] -> ClassFile -> Class,并放入方法区
	link(class)                         // 3. 进行链接
	fmt.Printf("[Loaded %s from %s]
", name, entry)
	return class
}

readClass 从classpath 读取 class []byte

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
}

defineClass 加载class

func (self *ClassLoader) defineClass(data []byte) *Class {
	class := parseClass(data)
	class.loader = self
	resolveSuperClass(class)          // 递归加载父类
	resolveInterfaces(class)          // 递归加载接口类
	self.classMap[class.name] = class // 放入已加载列表
	return class
}

// byte[] -> ClassFile -> 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) {
	interfaceCount := len(class.interfaceNames)
	if interfaceCount > 0 {
		class.interfaces = make([]*Class, interfaceCount)
		for i, interfaceName := range class.interfaceNames {
			class.interfaces[i] = class.loader.LoadClass(interfaceName)
		}
	}
}

link 链接class 给class赋初始值

func link(class *Class) {
	verify(class)  // 验证
	prepare(class) // 准备
}

// 准备阶段:给类变量分配空间并给予初始值
func prepare(class *Class) {
	calcInstanceFieldSlotIds(class) // 计算实例变量的个数,并分别标号
	calcStaticFieldSlotIds(class)   // 计算类变量的个数,并分别标号
	allocAndInitStaticVars(class)   // 为类变量分配空间并初始化
}

实战项目地址

https://gitee.com/yinlingchaoliu/jvmgo.git