电子说
❝根据《JAVA虚拟机规范》的规定,Class文件格式采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中(Class文件格式中)只有两种数据类型:“无符号数”和“表”。
❞
❝本篇文章图中贴出的类型这一列也都是这两个数据类型,如果类型是u开头的表示为无符号数的数据类型,如果是_info结尾的表示是表类型。
❞
❝u1在Class文件中为两个数字或字母,比如00,01,0A,6F ; u2在Class文件中为四个数字或字母,比如0001,000A,6C61;
❞
❝比如:cp_info为常量池表,field_info为字段表,method_info为方法表,attribute_info为属性表。本篇文章会讲解除了属性表之外的其他表结构,属性表单独写一篇文章进行讲解
❞
后面讲的所有结构都是按照这个Class文件表讲的,所以这张图先看下。
Class文件的 「头四个字节」 表示魔数,这个值存在于各个文件中,在之前的这篇文章里面讲过这个字段:验证apk文件的magic,magic是用来验证是不是属于某种结构的,即使用户更改了文件的后缀名也没事,通过这个字段就可以看出他是什么类型的文件。「因此每一种文件格式的魔数magic都不一样,因为是用来表示其属于哪种文件格式的。」
❝Class文件的magic为0XCAFFBABE(咖啡宝贝)
❞
接下来的两个字节表达的Class文件的 「次版本号(Minor Version)」 ,再接着两个字节表达的是 「主版本号(Major Version)」 。
❝高版本的JDK能够兼容低版本的Class文件,但是低版本的JDK不能运行高版本的Class文件(规范中Class文件校验必须要求的!)
❞
1、Class文件中第一个出现的表结构的数据,主要存放两种常量:「字面量和符号引用。」
❝字面量:Java语言层面常量的概念。eg:字符串,被声明为final的常量等
❞
❝符号引用:编译原理方面的概念。eg:被模块导出或者开放的包(Package) 类和接口的全限定名(也就是类所属的包名和类的名字) 字段的名称和描述符(名称简单理解就是字段名,描述符为字段所属的类型) 方法的名称和描述符(名称简单理解就是方法名,描述符为方法参数和返回值) 方法句柄和方法类型(Method Handle,Method Type,Invoke Dynamic) 动态调用点和动态常量
❞
2、符号引用,由于Class文件是在编译后生成的,因此运行的时候需要 「将符号引用转换为对应数据在内存中的地址」 ,否则使用的时候会找不到真正的内存入口地址(也就是不能被虚拟机直接使用)。
❝当虚拟机做类加载的时候,会从常量池中拿出对应的符号引用,在类创建或者运行时解析,翻译到具体的内存地址之中 比如class文件的类名,当类被加载到虚拟机中时,需要将这个符号引用转换为类真实所在的内存地址才能被正常访问。
❞
3.常量池中存储的数据数量 「从1开始计数」 ,第0项常量空出来是因为有些数据并不需要引用常量池中的数据时,就可以用第0项常量来表达。
4.常量池的数据数量会在版本号之后用两个字节来表达,之后才是常量池中的数据
❝这样做是因为没有Class文件中 「没有分隔符」 来表示一组数据结束,因此Class文件中的数据必须严格按照固定长度,固定数量去存放,不允许改变。
❞
5.常量池中 「每一项常量数据都是一张表」 ,每个表结构中都有一个u1类型的标志位标识自己属于哪种类型的表。
这些表有着各自完全独立的结构,之间没有任何关联。
C:\\>javap -verbose TestClass
Compiled from "TestClass.java"
public class org.fenixsoft.clazz.TestClass extends java.lang.Object SourceFile: "TestClass.java"
minor version: 0
major version: 50
Constant pool:
const #1 = class #2; // org/fenixsoft/clazz/TestClass
const #2 = Asciz org/fenixsoft/clazz/TestClass;
const #3 = class #4; // java/lang/Object
const #4 = Asciz java/lang/Object;
const #5 = Asciz m;
const #6 = Asciz I;
const #7 = Asciz ;
const #8 = Asciz ()V;
const #9 = Asciz Code;
const #10 = Method #3.#11; // java/lang/Object."":()V
const #11 = NameAndType #7:#8;// "":()V
const #12 = Asciz LineNumberTable;
const #13 = Asciz LocalVariableTable;
const #14 = Asciz this;
const #15 = Asciz Lorg/fenixsoft/clazz/TestClass;;
const #16 = Asciz inc;
const #17 = Asciz ()I;
const #18 = Field #1.#19; // org/fenixsoft/clazz/TestClass.m:I
const #19 = NameAndType #5:#6; // m:I
const #20 = Asciz SourceFile;
const #21 = Asciz TestClass.java;
代码块中Asciz就是之前说的Constant_UTF8_info常量(也就是字符串常量),可以看到这些数据都是由这个常量来组成的,
第一列常量为之前 「各个表对应的含义」 中提到的表结构类型也就是表的名称;
第二列中的项目为各个表中存放的不同的数据内容有哪些,这些表的数据中都有一个标识位tag用来标识不同的表,在之前 「各个表对应的含义」 中也提到过;
第三列为描述不同于之前讲的表的描述,这列说明的是**「表中存储的不同数据的描述」**
图例:
全部0条评论
快来发表一下你的评论吧 !