详解Class类文件的结构(下)

本文继续使用上次的Test.class文件,它是由下面单独的一个类文件编译而成的,没有包。

6. 索引(Index)

索引又分类索引、父类索引和接口索引集合,类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合(interfaces)是一组u2类型的数据的集合,Class文件依靠这些索引数据来确定这个类的继承关系。所有类(除了java.lang.Object)都只有一个父类索引(Java的单继承),即父类索引不为0,只有java.lang.Object的父类索引为0。接口索引用来描述该类实现了哪些接口,它们的出现顺序是按照implements语句后接口的先后顺序出现的,如果这个类是一个接口就按照extends后面出现的顺序来。

类索引和父类索引各自指向一个CONSTANT_Class_info的类描述符常量,然后通过CONSTANT_Class_info可以定位到一个CONSTANT_Utf8_info类型的常量中的全限名字符串。而接口索引集合则以接口计数器开头,和前面常量池类似,若计数器表示n则后面紧跟着的n个u2数据是表示该类实现的n个接口的类索引,分别指向对应的类描述符常量。

全限名:"java/lang/Object"表示Object类的全限名,将类全名中的“.”替换成“/”而已,多个全限名之间是“;”分隔。

仍然以我上次的那个Test.class文件为例,这里三个u2类型的值分别为Ox0005、Ox0006、Ox0000,前两个分别表示的是类索引、父类索引所指向的常量描述符。第三个表示接口集合的个数,这里为0即没有实现任何接口。假设为2,则表示接下来的2个u2数据表示实现的两个接口,每个u2数据也指向的是常量描述符。

7.字段表集合(Field Info)

字段表(field_info)用于描述接口或者类中声明的变量。字段包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。字段包含的信息比较多,包含以下内容:

  • 字段的作用域:public、private、protect修饰符
  • 变量类型(类变量or实例变量):static
  • 可变性:final
  • 并发可见性:volatile
  • 可否序列化:transient
  • 数据类型:基本数据类型、对象、数组
  • 字段名称

上面的这些信息除了字段数据类型和字段名称其他都是以布尔值来描述的,有就是true且对应一个标志位,没有则false,这种表示方法和上一节的Access Flags一样。字段数据类型和字段名称是引用的常量池中的常量来描述,可能是CONSTANT_Class_info也可能是CONSTANT_Utf8_info。

根据Java语言的语法我们可以知道,ACC_PUBLIC、ACC_PRIVATE、ACC_PROTECTED三个标志只能选一个,ACC_FINAL、ACC_VOLATILE不能同时存在,接口必须有ACC_PUBLIC、ACC_STATIC、ACC_FINAL标志。

描述符

描述符的作用是用来描述字段的数据类型、方法的参数列表(数量、类型、顺序)和返回值。其中基本数据类型以及void返回值类型都是用一个大写字母来表示的,对象的类型由一个L加对象全限名表示。

基本数据类型和普通类型都已经知道怎么表示了,但Java中有一个特殊类型就是数组类型,它是在编译期产生的,它的描述符是在变量描述符前面加一个"[",如果是二维则加两个[,比如"[["。例如一个String[][]记录为[[Ljava/lang/String,一个int[]记录为[I

如果是描述一个方法则在描述符前面加一个括号“()”,如果有参数则在其中按顺序添加描述符即可。例如一个String toString(char[] c,int a,String[] b)的描述符为:“([CI[Ljava.lang.String)Ljava.lang.String”。

这里同样以Test.class文件来验证,第一个u2数据是容量技术器fields_count,这里是Ox0000,说明没有字段表数据,看文章开头的java代码,确实没有定义任何字段。由于在编译class文件开始没有考虑周全,没有定义字段,这里容量技术器为0也就看不到后面的字段描述内容,这里先假设是Ox0001,即有一个字段。第二个u2数据是访问标识符access_flags,假设这里是Ox0002,说明字段标志为ACC_PRIVATE。第三个u2数据是字段名称name_index,假设值为Ox0005,指向#5的常量池CONSTANT_Utf8_info字符串。第四个u2数据是字段描述符,这里是Ox0007,指向#7的常量池字符串。

8. 方法表集合

方法表的描述和字段表集合描述形式一样,只需要按照对应的表格对照就可以了。方法表结构依次包含了access_flags(访问标志)、name_index(方法名索引)、descriptor_index(描述符索引)、attribute(属性表集合)几项。方法内的具体代码存放在属性表集合attribute的名为“Code”的属性里面。

方法表结构表:

方法访问标志表:

继续以Test.class文件分析,容量计数器methods_count的值为Ox0002,表示由两个方法,疑惑?看文章开头的代码只有一个main方法啊,为什么会有两个?其实字节码中包含了平时省略了的无参构造方法<init>。

紧跟着的是2个方法描述集合,这里以第一个无参构造来解释,首先是访问标志access_flags,值是Ox0001,查表可知是ACC_PUBLIC类型的,然后是方法名索引name_index,值是Ox0007,指向的是常量池CONSTANT_Utf8_info字符串,即#7,我们查看反编译的代码可以看到#7确实是<init>。

然后是描述符索引descriptor_index,值是Ox0008指向的是常量项#8,反编译后看到是()V,构造方法无返回值,所以用的void的标识字符V,但是在书写代码时不能显式加void,因为其验证是在编译期。紧接着的是属性表集合的属性计数量attributes_count,这里是Ox0001,说明只有一个属性,即前面说的“Code”属性。

接下来的就是分别表示每一个属性的具体指向,这里只有一个当然就只需看一个u2数据,这里是Ox0009,指向的是常量项#9,反编译结果#9确实是Code。

如果方法在子类中没有被重写,方法表集合中就不会出现来自父类的信息。

从方法表集合可以看出,Class文件对一个方法的特征识别(《Java虚拟机规范》称之为特征签名)有很多,比如方法描述符、访问控制标志、返回值、属性表等。

这里我想起来了之前腾讯一个面试官问我的问题“重载的验证是在哪个阶段?”,当时我没回答好这个问题,看了《深入理解Java虚拟机》这一节的内容才知道,对于Java方法的重载是在编译器验证的,在Java语义里规定:只要方法名、参数内容及顺序相同则视为非法重载,而对返回值、修饰符等没有严格要求。而在Class文件里对一个方法的特征签名比编译期的多,也就是说如果两个方法有相同的名称和特征签名,但返回值不同,那么也是可以合法存在于同一个Class文件的。

9.属性表集合

属性表(attribute_info)存在于Class文件、字段表、方法表等,它用于描述某些场合专有的信息。在class文件中对属性表的限定并不是很严格,只要不要与已有属性名重复,任何不人实现的编译器都可以向属性表中写入自己定义的属性信息,虚拟机在运行时会忽略掉它不认识的属性。这一部分内容较多并且不固定,建议读者阅读最新的《Java虚拟机规范》或《深入理解Java虚拟机——周志明 著》。

本文是笔者阅读《深入理解Java虚拟机》一书时的简单总结和实践。参考文献:《Java虚拟机规范(第二版)》、《深入理解Java虚拟机》

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/439493.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自动驾驶开源软件和算法库

1. Carla&#xff08;自动驾驶开源仿真软件&#xff09; github&#xff1a;https://github.com/carla-simulator/carladoc&#xff1a;https://carla.readthedocs.io/en/latest/website&#xff1a;http://carla.org/Bounding boxes&#xff1a;https://carla.readthedocs.io/…

Coursera自动驾驶课程第20讲:Mission Planning in Driving Environments

在第19讲《Coursera自动驾驶课程第19讲&#xff1a;Mapping for Planning》 我们学习了自动驾驶中两种环境建图方法&#xff1a;占用网格图&#xff08;occupancy grid map&#xff09; 和 高清地图&#xff08;high-definition road map&#xff09;。 在本讲中&#xff0c;我…

Java实例化对象过程中的内存分配

问题引入 这里先定义一个很不标准的“书”类,这里为了方便演示就不对类的属性进行封装了。 class Book{String name; //书名double price; //价格public void getInfo(){System.out.println("name:"name";price:"price);} } 在这个类中定义了两个属…

【Python学习】 - sklearn学习 - KNN

前言&#xff1a; 针对一个完整的机器学习框架目前还没有总结出来&#xff0c;所以目前只能总结每一个单独的算法。由于现在研究的重点是算法&#xff0c;所以对于数据的处理&#xff0c;数据的分析和可视化呈现&#xff0c;在现阶段并不进行展示&#xff08;这样容易陷入纠结…

重读经典:《End-to-End Object Detection with Transformers》

DETR 论文精读【论文精读】这一次朱毅博士给大家精读的论文是 DETR&#xff0c;是目标检测领域里程碑式的一个工作&#xff0c;文章收录于 ECCV20 。DETR 是 Detection Transformer 的缩写&#xff0c;作者使用 Transformer 简化了目标检测流程&#xff0c;不再需要进行 NMS&am…

Execute SQL Task 参数和变量的映射

Execute SQL Task能够执行带参数的SQL查询语句或存储过程&#xff08;SP&#xff09;&#xff0c;通过SSIS的变量&#xff08;Variable&#xff09;对参数赋值。对于不同的Connection Manager&#xff0c;在Task中需要使用不同的符号&#xff08;Parameter marker&#xff09;来…

【Python学习】 - 手写数字识别 - python读入mnist数据集的多种方法

写在前面&#xff1a; 其实网上有很多读入mnist数据的代码&#xff0c;但是都是比较麻烦冗长的函数&#xff0c;本篇文章介绍几种不算很麻烦的&#xff0c;借用库函数读入数据的方法。 方法1&#xff1a; 方法2&#xff1a; 方法3&#xff1a;

Coursera自动驾驶课程第21讲:Dynamic Object Interactions

在第20讲《Coursera自动驾驶课程第20讲&#xff1a;Mission Planning in Driving Environments》 我们学习了任务规划中常用的三种图搜索算法&#xff1a;Breadth First Search、Dijkstra 和 A* 搜索。 在本讲中我们将讨论运动规划器中使用的方法&#xff0c;以处理动态物体和…

sql server 数据库忘记sa账户密码/ 无管理员账户解决办法

一、计算机超级管理员账户有数据库的管理员权限 用管理员账户登录数据库&#xff0c;直接修改sa账户密码即可。 二、数据库中没有管理员权限的账户 SQL Server 2005/2008提供了针对该情况的更好的灾难恢复方法&#xff0c;无需侵入master数据库&#xff0c;不会对master数据库…

机器学习编译第1讲:机器学习编译概述

MLC-机器学习编译-第一讲-机器学习编译概述课程主页&#xff1a;https://mlc.ai/summer22-zh/ 文章目录1.0 概述1.1 什么是机器学习编译1.2 为什么学习机器学习编译1.3 机器学习编译的关键要素1.3.1 备注&#xff1a;抽象和实现1.4 总结1.0 概述 机器学习应用程序已经无处不在…

【Python学习】 - Pandas学习 sort_value( ),sort_index( )排序函数的区别与使用

按索引对DataFrame或Series进行排序&#xff08;注意ascendingfalse的意思是按照降序排序&#xff0c;若不写参数则默认升序排序&#xff09; DataFrame的构造函数默认参数是(值&#xff0c;列名&#xff0c;行索引)&#xff0c;行索引不填则默认0,1,2,3这样&#xff1f; In …

powerdesign 缩写AK,PK,IX,CK,FK,DF,UQ

PK - Primary Key IX - Non-Unique Index AK - Unique Index (AX should have been AK (Alternate Key)) CK - Check Constraint DF - Default Constraint FK - Foreign Key UQ - Unique Constraint

重读经典:《The Craft of Research(1)》

跟读者建立联系【研究的艺术一】这一次李沐博士给大家精读的是一本关于论文写作的书籍。这本书总共包含四个大的章节&#xff0c;本期视频李沐博士介绍的是第一个章节&#xff1a;Research&#xff0c;Researchers&#xff0c;and Readers。 0. 前言 视频开头&#xff0c;李沐…

【PAT - 甲级1045】Favorite Color Stripe(30分)(dp,LIS类问题)

题干&#xff1a; Eva is trying to make her own color stripe out of a given one. She would like to keep only her favorite colors in her favorite order by cutting off those unwanted pieces and sewing the remaining parts together to form her favorite color s…

机器学习编译第2讲:张量程序抽象

02 张量程序抽象 【MLC-机器学习编译中文版】课程主页&#xff1a;https://mlc.ai/summer22-zh/ 文章目录2.1 元张量函数2.2 张量程序抽象2.2.1 张量程序抽象中的其它结构2.3 张量程序变换实践2.3.1 安装相关的包2.3.2 构造张量程序2.3.3 编译与运行2.3.4 张量程序变换2.3.5 通…

迁移TFS 2012服务至新的电脑硬件

迁移TFS 2012的时候碰到一些问题, 中文记录很少, 英文的记录也比较零散. 这里记录最直接和简单的方法. 环境: 1. 公司域环境, 所有TFS用户都是公司域帐户. 2. TFS从一台服务器转移至另一台服务器. 都加入了公司域. 机器名分别为PC1和PC2. 域内不能有同名的电脑。 准备两台…

【PAT - 甲级1005】Spell It Right (20分) (递归输出,水题)

题干&#xff1a; Given a non-negative integer N, your task is to compute the sum of all the digits of N, and output every digit of the sum in English. Input Specification: Each input file contains one test case. Each case occupies one line which contain…

详解自动驾驶仿真数据集 SHIFT:A Synthetic Driving Dataset for Continuous Multi-Task Domain Adaptation

SHIFT&#xff1a;A Synthetic Driving Dataset for Continuous Multi-Task Domain Adaptation本文介绍一个新的自动驾驶仿真数据集&#xff1a;SHIFT&#xff0c;论文收录于 CVPR2022。适应连续变化的环境是自动驾驶系统一直以来要面临的挑战。然而&#xff0c;目前现有的图像…

TFS下的源代码控制

以下主要描述了&#xff1a; TFS源代码控制系统的基本场景如何把一个项目添加到源代码管理中如何与服务器同步如何做Check-In如何做分支与合并什么是上架与下架 我们知道工作项是项目管理的基本元素&#xff0c;但是一个项目的成功&#xff0c;光有工作项还是不够的。工作项说…

【PAT - 甲级1004】Counting Leaves (30分) (dfs,递归)

题干&#xff1a; A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members who have no child. Input Specification: Each input file contains one test case. Each case starts with a line containing 0<N<100,…