JVM001_类文件结构

无关性的基石

实现语言无关性的基础是虚拟机和字节码存储格式。Java虚拟机不与任何语言绑定(包括Java),它只与‘Class文件’这种特定的二进制文件格式所关联。Class文件中包含了Java虚拟机指令集、符号表以及其它辅助信息。出于安全考虑,《Java虚拟机规范》要求在Class文件中必须应用许多强制性的语法和结构化约束,但图灵完备的字节码格。

Class类文件的结构

Class文件是一组以8个字节为基础的二进制流,各项数据项目严格按照顺序紧凑的排列在文件中,中间没有任务分隔符。当遇到需要占用8个字节以上空间的数据项时,则会按照高位在前的方式分割成若干个8个字节进行存储。

高位在前: 高位的字节存储在内存中的低位。

例如:‘123456’ 那么1位高位的字节,6为低位的字节,加入有内存地址 012345,那么0中存1,1中存2.。。。5中存6,这种模式叫做高位在前,也叫大端。

Class文件结构中包括两种数据结构:‘无符号数’和‘表’。

  • 无符号数是基本数据类型。用u1,u2,u3,u4来分别表示1个字节、2个字节、3个字节、4个字节。
  • 表是由一系列无符号数或者其他表组成的复合数据结构。所有的表都习惯性的以”_info“结尾。

Class文件格式表: P215

img

魔数

魔数用来确定该文件是否为能被JVM所接受的Class文件。

现写两个Java类

package j1;public class Test {private String item = "itemStr";public String nothing(){return item;}
}
package j1;public class Test1 {private int count = 1;public int inc() {return count + 1;}
}

将其编译后,用notepad++或者sublime打开
在这里插入图片描述
在这里插入图片描述

可以看到在十六进制下,两个Class文件的头四个字节是cafebabe,这四个字节就是魔数。为什么说cafebabe是四个字节呢,因为这里是16进制,1个字节占8位,需要用两位十六进制符号表示,例如 11001101用十六进制表示应该为0XCD,简写为CD.

次版本号

紧跟着魔数后面的两个字节为次版本号
在这里插入图片描述

主版本号

在这里插入图片描述

​ 紧跟着次版本号后面的为主版本号,0034由16进制转换为十进制后为52,查询Class文件版本号可以找到JDK版本为JDK8.所以该文件能被JDK8及以上版本的虚拟机所执行。

常量池

主版本号后为常量池的的入口。常量池的入口放着一个u2类型的数据,用来表示常量池中常量的数目。
在这里插入图片描述

0013表示常量池中有18项常量,索引值范围为1-19。为什么0X0013转换为十进制后为19,但是这里说常量池中有18项常量呢?因为第一个常量存在索引为1的位置,这么做是考虑到后面某些指向常量池的索引值的数据在特定的情况下需要表达“不引用任何一个常量池项目”的含义,这个时候将索引值设为0即可来表示。

Class文件结构中只有常量池的容量计数是从1开始的,其余都是从0开始。

常量池中主要存放两大类常量: 字面量符号引用

字面量

  • 文本字符串
  • 被final修饰的常量等

符号引用

​ 符号引用输入编译原理方面的概念

  • 被模块导出或开放的包Packge
  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符
  • 方法句柄和方法类型
  • 动态调用点和动态常量

?描述符是什么?方法句柄是什么?动态调用是什么?动态常量是什么

截止JDK13一共有17中不同类型的常量。现总结为如下:
在这里插入图片描述

我们以Test1.class文件来分析

在这里插入图片描述

红框内的内容为常量池,其内容按照常量池项目图来按图索骥即可。

利用命令javap -v Test1.class或者javap -verbose Test1.class来反编译字节码文件,可以得到下图:

在这里插入图片描述

其中Constant pool下项目与16进制文件中红框内容对应。

访问标志

常量池结束后,紧接着的2个字节代表访问标志(access_flags),这个标志用来表示一些类或者接口层次的访问信息。

比如说这个Class是类还是接口,是否定义为Public类,是否为Abstract类,如果是类的话是否被声明为final等等。

access_flags一共有16个标志位可用,当前定义了其中的9个。没有使用到的标志位为0.因此,标志位的值也可以理解为是使用到的标志的位运算或。

图见: p224

类索引、父类索引、接口索引集合

类索引及父类索引都是一个u2类型的数据,接口索引集合是一组u2类型的数据的集合。这三项数据确定了改类型的继承及实现关系。

类索引确定了这个类的全限定名,父类索引确定了该类的父类的全限定名。除了java.lang.Object外其余类的父类索引都不为0.接口索引集合用来描述该类实现了哪些接口,这些被实现的接口安装implements关键字(若该类表示的是一个接口,那么应该为extends)后的接口顺序从左到右排列在索引集合中。对于接口索引集合,入口的第一项u2类型的数据为接口的计数器,表示索引表的容量,也就是实现了几个接口,若没有实现接口,则值为0。可以看到这里有点类似常量池的结构。

字段表集合

图见: p226-227

字段表用来描述接口或者类中声明的变量。包括类级变量以及实例级变量,但是不包括方法内部的局部变量。

全限定名: 将类的全限定名中".“用”/"代替后的字符串。

简单名称: 没有类型和参数修饰的方法或者字段。例如有个一方法public void test(int a,int b){},则该方法的简单名称为test。一个字段int a = 1;其简单名称为”a“。

描述符: 按照一定的规则来描述字段的类型、方法的参数列表(数量,类型及顺序)和返回值。

描述符标识字符含义见P227

描述符的一些规则

  • 对于数组,每增加一个维度就使用一个前置的“[”来表述,例如int[ ] [ ]对应的描述符为“[[I”。
  • 用描述符来描述方法时,按照先参数列表后返回指的顺序来描述。例如java.lang.String.toString()的描述符为()Ljava/lang/String。

字段表中可能会有一个属性集合表,用来存储一些额外的数据。

字段表集合中不会出现父类或者父接口中继承而来的字段,但可能出现一些代码中不存在的字段。对于Class文件格式来讲,只要两个字段的描述符不是完全相同的,那字段重名就是合法的。

方法表集合

结构与字段表集合类似。图见P229

方法中的Java代码存在方法属性表集合中一个名为“Code”的属性里面。

tip

  • 若父类方法没有在子类中重写,方法表集合中就不会出现来自父类的方法信息。
  • 在编译时,编译器可能向方发表自动添加方法,比如类构造器(“()”)、实例构造器("()")
  • Java中重载一个方法,需要与原方法具有相同的简单名称及与原方法不同的特征签名。特征签名是指一个方法中各个参数在常量池中的字段符号引用集合。返回值不包括在特征签名中。

属性表集合

这段内容有点烦躁,回头再看

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

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

相关文章

Maven学习(六)————企业Maven项目最佳实践

引言 在《Maven学习(三)————Maven核心概念(二)》中,学到了Maven 继承和 Maven 聚合的概念,这两个概念,解决的问题分别是: 1、解决一些公共依赖统一版本的问题。 2、统一打包部署…

JVM003_属性表

属性表 预备知识 javac -g Xxx.java 在生成class文件的时候生成所有调试信息javap -v Xxx.class 输出附加信息 属性表结构 类型名称数量备注u2attribute_name_index1属性名称索引,指向一个CONSTANT_Utf8_info型常量的索引u4attribute_length1该属性表的长度u1in…

Lombok ——自动化方法生成器

引言 此文为简单的Lombok 演示。 Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法。简而言之,一句话就是:通过简单的注解…

LeetCode(#26)————删除排序数组中的重复项

题目 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 示例 1: 给定数组 nums […

JVM006_类加载的过程

类加载 类加载时机 类加载的过程 新术语 类加载器 简单的理解为将类转换为二进制流的类或接口。 数组的元素类型 数组去掉所有维度的类型。 数组的组件类型 数组去掉一个维度的类型。 基本块 按照控制流拆分的代码块。 1. 加载 加载是类加载过程的一个阶段。加载阶段主…

服务端开发——云服务器的端口转发设置(SSH隧道)

引言 本篇博客介绍端口转发的知识,并详细阐述操作和设置步骤。这是因为在实际工作中,会有很多企业从安全的角度考虑,为线上或重要的服务器设置一个跳板机(堡垒机),避免远程开发人员直接操作,是…

Shiro————核心设计思想

引言 以此篇博客为引,开启一个新的专栏分类——Shiro。 之前在工作中有比较快速的学习过Shiro安全框架,但经过一年的荒废,已经不是很熟悉了,通过这个系列,深入研究和学习Shiro的一些知识,填补安全管理方面…

Web应用安全————账号冻结与 Session 实时失效

引言 开篇时说些题外话,最近刚刚被公司CY,不过很快找到了下家,也同时拿到了三家公司的Offer。一周面试下来,总体感觉面试题少了,不过多了上机程序题。新公司是做外包,不过相比于上一家公司,也算…

Web应用安全————Shiro 解决会话固定漏洞

引言 承接上一篇《Web应用安全————账号冻结与 Session 实时失效》关于 session 的学习,本篇博客聚焦如何通过 shiro 解决会话固定导致的漏洞问题。 首先,没怎么接触过应用安全方面的小伙伴可能会发起疑问 - 什么是会话固定? 简单来说&…

Web应用安全————多点登录互斥

引言 在实际生活中,很多网站都做了多点登录互斥的操作,简单来说就是同一个账号,只能在一台电脑上登录,如果有人在其他地方登录,那么原来登录的地方就会自动下线,再进行操作就会弹出登录界面。 实现思路 …

Linux进阶之路————磁盘查询

引言 承接《Linux进阶之路————Linux磁盘分区与挂载》,本文介绍实际生产中对于磁盘的监控和查询。 一、查询磁盘整体使用情况 基本语法: df -h 该命令会显示包括我们手动挂载的磁盘,如果使用 umount 卸载磁盘,那么将不会显示…

Linux进阶之路————CentOS网络配置

引言 Linux在装机后,如果没有特殊配置,会使用动态获取 IP 地址的策略。本文描述了,虚拟机使用网络的拓扑图,以及如何通过配置,将 IP 地址固定下来,不会因为重启而失效。同时可以访问外网地址。 一、NAT模…

Linux进阶之路————进程与服务管理

引言 在Linux 中,每个执行的程序(代码)都成为一个进程,Linux 为每一个进程分配了一个唯一的 id 号 - PID。 每个进程都会对应一个父进程,而这个父进程可以复制多个子进程,例如 www 服务器。 每个进程都可…

Linux进阶之路———— RPM 与 YUM 包管理

引言 rpm 是一种用于互联网下载的打包及安装工具,它包含在某些 Linux 发行版中,生成具有 .rpm 扩展名的文件。rpm 是 redhat package manager(RedHat 软件包管理器)的缩写,类似 Windows 下的 setup.exe 文件。这一文件…

Linux进阶之路———Shell 编程入门

引言 通过 Shell 编程的学习,铺平架构师道路上的一块大砖。 Shell 在Linux 系统中的定位如下所示: 一、第一个 Shell 脚本 我们通过一个简单的 Shell 脚本来感受一下。 在 Shell 中不需要加 “;” 结尾,通过 vim 可以进行 shell 的编程工…

Linux 实操———CentOS 6 安装配置 Oracle JDK 1.8

引言 本篇博客也属于Linux进阶系列,主要讲解如何在CentOS 6 下安装并配置 JDK 8。由于通过 yum 搜索的结果都是 openjdk,而目前企业中还是以 Oracle jdk 为主,因此,操作步骤这样的。 在Oracle 官网把 jdk 1.8 下载下来&#xff…

Linux 实操———CentOS 6 安装配置 Tomcat

引言 Linux下安装Tomcat。 一、下载、传输与解压 同《Linux 实操———CentOS 6 安装配置 Oracle JDK 1.8》一样,前期都是先在远程机上下载压缩包,然后通过远程终端,将压缩包放在 Linux 的 opt 目录下,然后解压。 下载地址是T…

Spring Boot 实用开发技巧————Eclipse 远程调试

引言 在之前的开发当中,都会进行本地项目启动,然后向本地服务发起请求来进行 Debug 调试代码,这也是开发人员最常见的调试操作。但是当项目逐渐成型,慢慢的将各个模块部署到服务器后,调试的手段可能就仅仅剩下查看执行…

Linux 实操———— Shell 远程执行命令

引言 目前,开发人员的部署方式是,将项目打包(Maven 打包) 然后将 生成的 jar 包等文件,通过Xshell 等终端工具手动传输到远程服务器上,然后再通过在终端执行远程服务器上的 shell 脚本来启动服务。 本篇博客聚焦这样一种解决方案…

Spring Boot 设置 ASCII banner 艺术字

引言 无意中看到Spring boot 项目的 resources 目录下有一个 banner.txt ,打开一看,居然是ASCII 字符画。于是兴起,简单研究了一下。 Spring boot 可以加载 resources 目录下的 banner.txt 文件,将字符画在启动之初输出到日志或…