class文件

本文详细解读了Java Class文件的构成,包括魔数、版本信息、常量池、访问标志、字段表和方法表等内容,展示了如何使用javap-verbose命令分析字节码并介绍了Class文件中的数据类型和结构特点。

class文件

8位字节为基础单位的二进制流。

当遇到8位字节以上的空间的数据项时,则会按照高位在前的方式分割成若干个8位字节进行存储。

Class文件中有两种数据类型,分别是无符号数和表。 (基本数据类型与引用数据类型)

节省存储空间,提高系统性能

魔数:开头4个字节

package com.jvm.bytecode.java01;

public class MyTest {
    private int a = 1;

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }
}

查看反编译文件 javap -verbose

G:\javaSE_Mode\JVMDemo\out\production\JVMDemo\com\jvm\bytecode\java01>javap -verbose MyTest.class
在这里插入图片描述

二进制文件(工具Binary Viewer)
在这里插入图片描述

cmd命令:javap -verbosc

使用javap -verbosc命令分析一个字节码文件时,将会分析该字节码文件的魔数、版本号、常量池、类信息、类的构造方法、类中的方法信息、类变量与成员变量等信息。

魔数

魔数:所有的.class 字节文件的前4个个字节都是魔数,魔术值为固定值: 0xCAFEBABE;

不是以此开头的一定不是合法的.class字节文件,虚拟机不会加载此文件。

在这里插入图片描述

版本号

魔数之后的4个字节为版本信息,前两个字节表示minor version(次版本号),后两个字节表示ajor version(主版本号)。这里的版本号为00 00 00 37,换算成十进制,表示次版本号为0,主版本号为52。所以。该文件的版本号为∶11.0.0。可以通过java -version命令来验证这一点。
在这里插入图片描述
在这里插入图片描述

常量池

常量池(constant pool)∶紧接着主版本号之后的就是常量池入口。一个Java类中定义的很多信息都是由常量池来维护和描述的。可以将常量池看作是clas这文件的资源仓库,比如说iava类中定义的方法与变量信息,都是存储在常量池中。

常量池中主要存储两类常量∶字面量与符号引用。字面量如文本字符串,Java中声明为final的常量值,方法引用和变量等,而符号引用如类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符等。

常量池总体结构:

Java类所对应的常量池主要由常量池数量与常量池数组这两部分共同构成。常量池数量紧跟在主版本号后面,占据2个字节;常量池数组则紧跟在常量池数量之后。常量池数组与一般的数组不同的是,常量池数组中不同的元素的类型、结构都是不同的,长度当然也就不同;但是,每一种元素的第一个数据都是一个u1类型,该字节是个标志位,占据1个字节。JVM在解析常量池时,会根据这个u1类型来获取元素的具体类型。

常量池数量

在这里插入图片描述
值得注意的是,常量池数组中元素的个数 =常量池数 -1 (其中0暂时不使用),目的是满足某些常量池索引值的数据在特定情况下需要表达【不引用任何一个常量】池的含义;根本原因在于,索引为0也是一个常量(保留常量),只不过它不位于常量表中,这个常量就对应null值;所以。常量池的索引从1而非0开始。
在这里插入图片描述

常量池数组

常量池数组则紧跟在常量池数量之后。常量池数组与一般的数组不同的是,常量池数组中不同的元素的类型、结构都是不同的,长度当然也就不同;但是,每一种元素的第一个数据都是一个u1类型,该字节是个标志位,占据1个字节。JVM在解析常量池时,会根据这个u1类型来获取元素的具体类型。
在这里插入图片描述

第一个常量

无返回值的构造方法 --init 构造方法
在这里插入图片描述
在这里插入图片描述
在JVM规范中,每个变量/字段都有描述信息,描述信息主要的作用是描述字段的数据类型、方法的参数列表《包括数量、类型与顺序)与返回值。根据描述符规则,基本数据类型和代表无返回值的void类型都用一个大写字符来表示,对象类型则使用字符z加对象的全限定名称来表示。为了压缩字节码文件的体积,对于基本数据类型,JvM都只使用一个大写字母来表示,如下所示:B - byte, C - char,D - double,F - float, I - int,J - long,S - short,Z - boolean,V - void,z-对象类型,如Ljava/lang/String

对于数组类型来说,每一个维度使用一个前置的[来表示,如int [ ]被记录为[I,String[ ][ ]被记录为[[Ljava/lang/String;

用描述符描述方法时,按照先参数列表,后返回值的顺序来描述。参数列表按照参数的严格顺序放在一组( )之内,如方法:string getRealnamebyTdAndtickname(int id,String name)的描述符为:(I,Ljava/lang/string;)Ljava/lang/string;

第二个常量

在这里插入图片描述

第三个常量

在这里插入图片描述

其他常量在这里插入图片描述
字节码整体结构

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Class字节码中有两种数据类型
字节数据直接量:这是基本的数据类型。共细分为u1,u2、u4、u8四种,分别代表连续的1个字节、2个字节、4个字节、8个字节组成的整体数据。
表(数组):表是由多个基本数据或其他表,按照既定顺序组成的大的数据集合。表是有结构的,它的结构体现在:组成表的成分所在的位置和顺序都是已经严格定义好的。

访问标志

访问标志信息包括该Class文件是类还是接口,是否被定义成public,是否是abstract,如果是类,是否被声明成final。通过上面的源代码,我们知道该文件是类并且是public。
在这里插入图片描述
多个修饰符相加为最后的结果;不会单独列出每一个
在这里插入图片描述
在这里插入图片描述

类名与父类名

在这里插入图片描述
在这里插入图片描述

字段表 fields

方法表的结构

字段表用于描述类和接口中声明的变量。这里的字段包含了类级别变量以及实例变量,但是不包括方法内部声明的局部变量

类型名称含义数量
u2access_flags访问标志1
u2name_index字段名索引1
u2descriptor_index描述符索引1
u2attributes_count属性计数器1
attribute_infoattributes属性集合attributes_count

访问标志

标志名称标志值含义
ACC_PUBLIC0x0001字段是否为 public
ACC_PRIVATE0x0002字段是否为 private
ACC_PROTECTED0x0004字段是否为 protected
ACC_STATIC0x0008字段是否为 static
ACC_FINAL0x0010字段是否为 final
ACC_VOLATILE0x0040字段是否为 volatile
ACC_TRANSTENT0x0080字段是否为 transient
ACC_SYNCHETIC0x1000字段是否为由编译器自动产生

在这里插入图片描述

方法表

第一个方法
在这里插入图片描述

方法表的结构

类型名称含义数量
u2access_flags访问标志1
u2name_index方法名索引1
u2descriptor_index描述符索引1
u2attributes_count属性计数器1
attribute_infoattributes属性集合attributes_count

attribute_info

类型名称数量含义
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u1infoattribute_length属性表

JVM预定义了部分attribute,但是编译器自己也可以实现自己的attribute写入class文件里,供运行时使用。
不同的attribute通过attribute_name_index来区分

Code_attribute属性表结构
在这里插入图片描述
attribute_length:表示attribute所包含的字节数,不包含attribute_name_index和attribute_length
max_stacks:表示这个方法运行的任何时刻所能达到的操作数栈的最大深度
max_locals:表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量
code_length:表示该方法所包含的字节码的字节数以及具体的指令码。具体的字节码是指该方法被调用时,虚拟机所执行的字节码
exception_table:存放处理异常的信息,每个exception_table表,是由start_pc、end_pc、hangder_pc、catch_type组成
start_pc、end_pc:表示在code数组中从start_pc到end_pc(包含start_pc,不包含end_pc)的指令抛出的异常会由这个表项来处理
hangder_pc:表示处理异常的代码的开始处。
catch_type:表示会被处理的异常类型,它指向常量池中的一个异常类。当catch_type=0时,表示处理所有的异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岿然如故

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值