class文件结构
字节码只代表程序逻辑,只是Class文件众多组成部分其中之一。
语言无关性
很多语言都可以编译成class文件,如java,rb,groovy等。
文件结构
Class文件格式版本号及各部分的数量与大小。
魔数与版本
- 魔数定义了文件是Java类型的文件。比如在图片文件的开头,也有定义图片的类型的魔数。
- 版本号告知JVM是否能执行文件中的代码。比如低版本jdk无法执行高版本jdk编译出的class文件。
关于为什么魔数不叫JAVA叫CAFEBEAN,这是James Gosling 的解释
We used to go to lunch at a place called St Michael’s Alley. According to local legend, in the deep dark past, the Grateful Dead used to perform there before they made it big. It was a pretty funky place that was definitely a Grateful Dead Kinda Place. When Jerry died, they even put up a little Buddhist-esque shrine. When we used to go there, we referred to the place as Cafe Dead. Somewhere along the line, it was noticed that this was a HEX number. I was re-vamping some file format code and needed a couple of magic numbers: one for the persistent object file, and one for classes. I used CAFEDEAD for the object file format, and in grepping for 4 character hex words that fit after “CAFE” (it seemed to be a good theme) I hit on BABE and decided to use it. At that time, it didn’t seem terribly important or destined to go anywhere but the trash can of history. So CAFEBABE became the class file format, and CAFEDEAD was the persistent object format. But the persistent object facility went away, and along with it went the use of CAFEDEAD – it was eventually replaced by RMI.
从网上找了jdk各个版本对应的十六进制数和十进制数
常量池
结构
- constant_pool_count u2
从u2的大小可知,常量池最多能包含65536个条目(2^16)。每个条目可以是不同的类型,因此他的长度是可变的。 - constant_pool cp_info
常量池名称 | 常量池名称表示值 | 常量池名称表示值 |
---|---|---|
CONSTANT_Utf8 | 1 | UTF-8编码的字符串(2byte) |
CONSTANT_Integer | 3 | Java int (4 bytes) |
CONSTANT_Float | 4 | Java float (4 bytes) |
CONSTANT_Long | 5 | Java long (8 bytes) |
CONSTANT_Double | 6 | Java double (8 bytes) |
CONSTANT_Class | 7 | class name |
CONSTANT_String | 8 | String 常量 – index of a Utf8 entry |
CONSTANT_Fieldref | 9 | 字段引用 – name and type, class |
CONSTANT_Methodref | 10 | 方法引用 – name and type, class |
CONSTANT_InterfaceMethodref | 11 | 接口方法引用 |
CONSTANT_NameAndType | 12 | 字段或方法的部分符号引用 |
- 常量池条目
很多常量池条目引用其他常量池条目。
Fieldref
index to a Class
index to a Utf8 (name of class containing it)
index to a NameAndType
index to a Utf8 (name of field)
index to a Utf8 (type descriptor)
类、超类、接口的访问符
(1)this class u2
-指向常量池的Class。
(2)super class u2
-指向常量池的class
(3)interface_count u2
-接口数量
(4)interfaces
-interface_count个interface u2
-每个interface是指向CONSTANT_Class的索引
(5)field count
-字段数量
(6)fields
-field_count个field info
(7)field
-access flags u2
-name index u2
-descriptor index u2
-attributes count u2
-attribute info attributes[attributes count]
字段
方法
方法信息中最主要的是字节码,其次包括
- 异常处理器表
- 操作数栈与局部变量区大小
- 操作数栈的类型记录( StackMapTable, Java 6开始)
- 调试用符号信息(如LineNumberTable、 LocalVariableTable),对应Java源代码中“诧句”不“表达式”对应癿信息
属性
有关exception_table 表示,在start_pc和end_pc之间,如果遇到catch_type异常或者它的子异常,则转到handler_pc处理。
不要和Code中的Exception table混淆。
Class文件类型文件校验
Class文件结构的例子
从字节码引出的几个问题
1.为什举ASM无法从接口类型上的方法取得参数的名称?比如Mybatis的接口,反编译后会失去参数名称。
这是因为参数名跟局部变量名都保存在LocalVariableTable;返个属性表跟方法体联系在一起,而接口的方法没有方法体。
2. import时每个类型名都写出来与使用*通配符有什么不同?
从Class文件来看没有任何不同,只不过使用通配符增加了源码中名字冲突的可能性而已。
JVM字节码执行
创建对象
当JVM收到一个new指令等其他5个指令时,会检查指令中的参数在常量池是否有这个符号的引用。
https://crossoverjie.top/JCSprout/#/jvm/newObject