《自己动手写Java虚拟机》学习笔记(三)

第三章 解析.class文件

本章与.class文件结构息息相关。笔者将以书中顺序解释jvm思想。

3.1 .class文件

.class文件是类(或接口)信息的载体,每一个.class文件都完整定义了一个类。虽然jvm规范对从哪里加载class文件给与足够的自由,但是却对.class文件的结构给了严格定义。

可以把.class文件当作字节流,但是很不方便,所以将其取出设置成byte[]数组。

a.定义ClassReader结构体。

本结构体用来“读”.class文件。其内部只有.class文件构成的byte[]数组。每当“读”一部分后,就会按照该部分大小,对byte[]进行重置。(因为读了一部分后,这部分已经没有用了!假定有一个头指针,则头指针应该后移相应的字节数。但是在Go语言中,可以实现如:data=data[1:]; 的语句,意思是,把data数组从下标为1开始的数组赋给data,即data指向原data[1])

b.解析.class文件

通过一个结构体来对应整个.class文件。则这个结构体需要:1.魔数 2.次版本号 3.主版本号 4.常量池 5.类访问权限 6.指向本类对象的this指针 7.父类 8.实现的接口 9.字段名字 10.方法名字 11.类属性表。

在其中一个read()方法中,使用定义的ClassReader依次读字节信息,存放到相应的位置。

c.解析字段和方法表

字段表和方法表分别存储字段和方法信息。两者差别只在属性表中。

在读字段表和方法表中,都有一个数量来控制这个表的长度。那么我们解析的时候,需要先得到这个长度L,然后进行L次循环得到表的每一项。由于属性表自带长度,所以解析时不必担心出现问题。

d.解析常量池

常量池实际上也是一个表,但是有三点要特别的注意:

①表头给出的常量池大小比实际长度少1。如果长度为N,则共有N项

②有效的索引值是1~N-1。

③CONSTANT_Long_info和CONSTANT_Double_info各占两个位置。即表中的实际数量比N-1还要小。

那么我们可以把一个常量项抽象成一个数据类型。了解JVM字节码应该清楚,每一个常量项都有一个tag属性,根据其tag值的不同,按照不同的规则进行解析。

常量池中的常量分成两类:字面量和符号引用。字面量包括数字常量和字符串常量,符号引用包括类接口、字段和方法信息等。除了字面量,其他常量都是通过索引直接或间接指向CONSTANT_Utf_8_info常量。

e.解析属性表

属性表可以看作是一个大杂烩,它包括了方法字节码等信息。属性不同于常量,是可以自由扩展的。因此java虚拟机规范没有用tag区分,而是使用了属性名来区分不同的属性。

解析属性表时,依然要根据个数来进行读取。

当处理到属性项时,会根据其在常量表中的索引得到属性名。再根据属性名对字节码进行解析。

3.2 Go语法规则

1.Go数据类型

Go和Java语言基本数据类型对照关系
Go语言类型 Java语言类型 说明
int8 byte 8比特有符号整数
uint8(别名byte)   8比特无符号整数
int16 short 16比特有符号整数
uint16 char 16比特无符号整数
int32(别名rune) int 32比特有符号整数
uint32   32比特无符号整数
int64 long 64比特有符号正数
uint64   64比特无符号整数
float32 float 32比特IEEE-754浮点数
float64 double 64比特IEEE-754浮点数

2.访问控制

只分为公开和私有。所有首字母大写的类型、结构体、字段、变量、函数、方法等等等等都是公开的,可供其他包的使用。所都首字母小写的都是私有的。

3.3 直击内心

这是本章最后引自David Wheeler的名言,与诸君分享:

“ALL problems in computer science can be solved by another level of indirection.”

猜你喜欢

转载自blog.csdn.net/monkeydcoding/article/details/81289807