JVM入门之Class结构介绍1

电子说

1.3w人已加入

描述

Class文件规范

❝根据《JAVA虚拟机规范》的规定,Class文件格式采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中(Class文件格式中)只有两种数据类型:“无符号数”和“表”。

❝本篇文章图中贴出的类型这一列也都是这两个数据类型,如果类型是u开头的表示为无符号数的数据类型,如果是_info结尾的表示是表类型。

  1. 无符号数就是正常的数字,以u1,u2,u4,u8来表示一个,两个,四个,八个字节,通常用来描述数字,索引引用,数量值或者用来表达字符串值。

❝u1在Class文件中为两个数字或字母,比如00,01,0A,6F ; u2在Class文件中为四个数字或字母,比如0001,000A,6C61;

  1. 表是用来描述复合结构的数据,它由无符号数或者其他表构成,并在结尾处用“_info”表示。

❝比如:cp_info为常量池表,field_info为字段表,method_info为方法表,attribute_info为属性表。本篇文章会讲解除了属性表之外的其他表结构,属性表单独写一篇文章进行讲解

  1. 本质上Class结构也是将表和无符号数组合起来的一张表。

Class文件大结构总览

后面讲的所有结构都是按照这个Class文件表讲的,所以这张图先看下。Class

magic

Class文件的 「头四个字节」 表示魔数,这个值存在于各个文件中,在之前的这篇文章里面讲过这个字段:验证apk文件的magic,magic是用来验证是不是属于某种结构的,即使用户更改了文件的后缀名也没事,通过这个字段就可以看出他是什么类型的文件。「因此每一种文件格式的魔数magic都不一样,因为是用来表示其属于哪种文件格式的。」

❝Class文件的magic为0XCAFFBABE(咖啡宝贝)

Class文件版本号

接下来的两个字节表达的Class文件的 「次版本号(Minor Version)」 ,再接着两个字节表达的是 「主版本号(Major Version)」

❝高版本的JDK能够兼容低版本的Class文件,但是低版本的JDK不能运行高版本的Class文件(规范中Class文件校验必须要求的!)

Constant_Pool常量池

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类型的标志位标识自己属于哪种类型的表。

各个表对应的含义

这些表有着各自完全独立的结构,之间没有任何关联。Class

反编译代码示例

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用来标识不同的表,在之前 「各个表对应的含义」 中也提到过;

第三列为描述不同于之前讲的表的描述,这列说明的是**「表中存储的不同数据的描述」**

图例:ClassClass

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分