文章目录
一、概要
上篇我们定义了class文件的结构体,这节我们主要实现把class文件读取到内存,注意我们的目的很简单,就是读取字节流解析class文。不会现在处理一些过多的内容。
在class.go文件定义ClassBytes结构体
type ClassBytes struct {
Bytes []byte
Class *Class
}
Bytes是当前读取class文件的字节,Class是需要解析的Class结构体的指针。
二、调整结构体
上节我们定义的结构体做一些简单调整
type Class struct {
Magic uint32 `json:"magic"` // 魔数
MinorVersionMin uint16 `json:"minor_version_min"` // 副版本号
MinorVersion uint16 `json:"minor_version"` //主版本号
ConstantPoolCount uint16 `json:"constant_pool_count"` //常量池计数器
ConstantPoolInfo []ConstantPoolInfo `json:"constant_pool_info"` // 常量池
AccessFlags uint16 `json:"access_flags"` //访问标志
ThisClass uint16 `json:"this_class"` //类索引,
SuperClass uint16 `json:"super_class"` //父类索引,
InterfaceCount uint16 `json:"interface_count"` //接口计数器
interfaces []interface{
} `json:"interfaces"` //接口表
FieldsCount uint16 `json:"fields_count"` //字段计数器
FieldInfo []interface{
} `json:"field_info"` //字段表
MethodCount uint16 `json:"method_count"` //方法计数器
MethodInfo []*Method `json:"method_info"` //方法表
AttributesCount uint16 `json:"attributes_count"` //属性计数器
AttributeInfo []Attribute `json:"attribute_info"`
}
我们把[]interface{} 类型能确定的替换成了具体的类型,并且加入了json标签,用于打印一下class的内容,另外由于篇幅的原因,此处不粘贴其它结构体的代码了,我会在文章结尾添加当天的代码下载地址,也会在本篇绑定资源下载,读者可以自行下载代码查阅,这里只粘贴Class
三、解析class
1、在class.go文件定义 AnalysisClass方法
` 提示:请读者理解go语言的方法和函数的区别,方法有接收者调用的时候需要变量.func()这样子来调用,类比java可以把方法看成是对象方法,函数看成是静态方法
func (C *ClassBytes) AnalysisClass() {
class := C.Class
//解析魔数
class.Magic = binary.BigEndian.Uint32(C.Bytes[:4])
//小版本号
class.MinorVersionMin = binary.BigEndian.Uint16(C.Bytes[4:6])
//大版本号
class.MinorVersionMin = binary.BigEndian.Uint16(C.Bytes[6:8])
//读取常量池
class.ConstantPoolCount = binary.BigEndian.Uint16(C.Bytes[8:10])
//去除已经读过的字节
C.Bytes = C.Bytes[10:]
if class.ConstantPoolCount != 0 {
//调用常量池读取方法
pool := C.AnalysisClassReadeConstantPool(int(class.ConstantPoolCount))
class.ConstantPoolInfo = pool
}
//访问控制
class.AccessFlags = binary.BigEndian.Uint16(C.Bytes[:2])
//类索引
class.ThisClass = binary.BigEndian.Uint16(C.Bytes[2:4])
//父类
class.SuperClass = binary.BigEndian.Uint16(C.Bytes[4:6])
//接口计数器
class.InterfaceCount = binary.BigEndian.Uint16(C.Bytes[6:8])
//先去除读过的字节
C.Bytes = C.Bytes[8:]
//判断是否用接口
if class.InterfaceCount != 0 {
//解析接口
}
//字段计数器
class.FieldsCount = binary.BigEndian.Uint16(C.Bytes[:2])
//先去除读过的字节
C.Bytes = C.Bytes[2:]
//判断是否有字段
if class.InterfaceCount != 0 {
//解析字段
}
//方法计数器
class.MethodCount = binary.BigEndian.Uint16(C.Bytes[:2])
//先去除读过的字节
C.Bytes = C.Bytes[2:]
//判断是否有方法
if class.MethodCount != 0 {
//解析方法
method := C.AnalysisClassReadeMethod(int(class.MethodCount))
class.MethodInfo = method
}
//属性计数器
class.AttributesCount = binary.BigEndian.Uint16(C.Bytes[:2])