深入浅出JVM(四)之类文件结构

深入浅出JVM(四)之类文件结构

Java文件编译成字节码文件后,通过类加载机制到Java虚拟机中,Java虚拟机能够执行所有符合要求的字节码,因此无论什么语言,只要能够编译成符合要求的字节码文件就能够被Java虚拟机执行

Java虚拟机和字节码是语言、平台无关性的基石

本篇文章将深入浅出的解析字节码文件

无关性的基石

曾经: 源代码->经过编译->本地机器码

Java: 源代码->经过编译->字节码 -> 解释器 -> 本地机器码

image-20210508090007130.png 字节码: 与操作系统和机器指令集无关的,平台中立的程序编译后的存储格式

字节码是无关性的基石

平台无关性的基石:

  1. 所有平台都统一支持字节码
  2. 不同的Java虚拟机都可以执行平台无关的字节码

因此实现了 一次编译,到处运行

语言无关性的基石:

  1. Java虚拟机
  2. 字节码

Java虚拟机不是只可以执行Java源代码编译而成的字节码,只要符合要求(安全...)的字节码,它都可以执行

因此Kotlin...等语言可以运行在Java虚拟机上

Class类文件结构

文件格式存取数据的类型

  1. 无符号数 : u1,u2,u4,u8代表1,2,4,8个字节的无符号数(可以表示数字,UTF-8的字符串,索引引用....)
  2. 表: 由n个无符号数或n个表组成(命名以_info结尾)
初识Class文件格式

编写Java源代码

 public class Test {
     private int m;
     private final int CONSTANT=111;
 ​
     public int inc() throws Exception {
         int x;
         try {
             x = 1;
             return x;
         }catch (Exception e){
             x = 2;
             return  x;
         }finally{
             x = 3;
         }
     }
 }

使用可视化工具classpy查看反编译的结果

image-20201107172118033.png 每个集合前都有一个计数器来统计集合中元素的数量

Class文件格式的描述

数据类型名称数量对应图中名字作用
u4magic1魔数确定这个文件是否是一个能被虚拟机接受的Class文件
u2minor_version1次版本号虚拟机必须拒绝执行超过其版本号的Class文件
u2major_version1主版本号虚拟机必须拒绝执行超过其版本号的Class文件
u2constant_pool_count1常量池容量计数器统计常量数量
cp_infoconstant_poolconstant_pool_count - 1常量池存放常量
u2access_flags1访问标志识别类(类,接口)的访问信息
u2this_class1类索引确定类的全限定名
u2super_class1父类索引确定父类的全限定名
u2interfaces_count1接口计数器统计该类实现接口数量
u2interfacesinterfaces_count接口索引集合描述该类实现了的接口
u2fields_count1字段表集合计数器统计类的字段数量
field_infofieldsfields_count字段表集合描述类声明的字段(类变量,实例变量)
u2methods_count1方法表集合计数器统计类的方法数量
method_infomethodsmethods_count方法表集合描述类声明的方法
u2attribute_count1属性表集合计数器统计属性数量
attribute_infoattributesattributes_count属性表集合描述属性
魔数与主次版本号
  • 魔数: 确定这个文件是否为一个能被虚拟机接受的有效Class文件

  • 主次版本号: 虚拟机拒绝执行超过其版本号的Class文件

    • 不同版本的Java前端编译器编译生成对应的Class文件主次版本号不同
    • 支持高版本JVM执行低版本前端编译器生成的Class文件(向下兼容)
    • 拒绝低版本JVM执行高版本前端编译器生成的Clsss文件
常量池

常量池包含两大常量: 字面量和符号引用

符号引用与直接引用

  • 符号引用

    • 使用一组符号描述引用(为了定位到目标引用)
    • 与虚拟机内存布局无关
    • 还是符号引用时目标引用不一定被加载到内存
  • 直接引用

    • 直接执行目标的指针,相对偏移量或间接定位目标引用的句柄
    • 与虚拟机内存布局相关
    • 解析直接引用时目标引用已经被加载到内存中

字面量与符号引用

  • 字面量

    • 文本字符串
    • 被final声明的常量
  • 符号引用

    • 全限定名
    • 方法或字段的简单名称和描述符

image-20210512225657765.png 图中的常量有我们代码中熟悉的常量也有很多没有显示出现在代码中的常量

访问标志

用于识别类或接口的访问信息

是否是一个接口,枚举,模块,注解...

是否被final(public,abstract...)修饰

image-20201107175942225.png ACC_PUBLIC:被public修饰

ACC_SUPER: 允许使用invokespecial字节码指令

类索引,父类索引与接口索引集合

类索引

用于确定本类的全限定名

image-20201107180153111.png 类索引指向常量池中表示该类的符号引用

父类索引

用于确定父类的全限定名

image-20201107180509860.png

父类索引指向常量池中表示该类父类的符号引用

除了Object外,所有类的父类索引都不为0

接口索引集合

描述这个类实现了哪些接口

我们的例子中没有实现接口,就没有(接口索引集合计数器为0)

总结

Class文件由 类索引,父类索引,接口索引集合 来确定该类的继承关系

字段表集合

描述类声明的字段

字段包括类变量和成员变量(实例变量),不包括局部变量

image-20201107181355881.png

简单名称和描述符

  • 简单名称

    • 字段: 没有描述字段类型的名称
    • 方法: 没有描述参数列表和返回类型的名称
  • 描述符

    • 字段: 描述字段的类型

    • 方法: 描述参数列表和返回值

    • 描述符字符含义(long,boolean,对象类型是J,Z,L 其他都是首字母大写)

      标识字符含义
      Bbyte
      Cchar
      Ddouble
      Ffloat
      Iint
      Jlong
      Sshort
      Zboolean
      Vvoid
      L对象类型,如Ljava/lang/Object
    • 描述符描述n维数组

      • 在前面先写n个[ 再写标识字符

        比如java.lang.Integer[ ] => [Ljava.lang.Integer

    • 描述符描述方法

      • 参数列表按照从左到右的顺序写在()

      • 返回类型写到最后

        比如String method(long[],int,String[]) => ([JIL[java.lang.String)Ljava.lang.String

因此Class文件中字段描述符指向常量池中的#07 I 符号引用(的索引)

注意

  1. 字段表集合不会列出父类或父接口中声明的字段

  2. 只用 简单名称 来确定字段,所以不能有重名字段

  3. 用 简单名称 和 描述符 确定方法,所以方法可以重名(重载)

    • 字节码文件 规定 简单名称+描述符相同才是同一个方法
    • 但是 Java语法 规定 重载 = 简单名称相同 + 描述符的参数列表不同 + 描述符的返回类型不能不同
方法表集合

描述类声明的方法

与字段表集合类似

image-20201107182407009.png

注意

方法表集合中不会列出父类方法信息(不重写的情况)

属性表集合

属性比较多,这里只说明我们例子中出现的,其他的会总结

用于描述某些场景专有信息

刚刚在字段,方法表集合中都可以看到属性表集合,说明属性表集合是可以被携带的

怎么没看到Java源代码中的代码呢?

实际上它属于属性表集合中的Code属性

Code属性

Java源代码中方法体中的代码经过编译后编程字节码指令存储在Code属性内

image-20201107184345952.png 其中的异常表集合代表 编译器为这段代码生成的多条异常记录,对应着可能出现的代码执行路径

(程序在try中不抛出异常会怎么执行,抛出异常又会怎么执行....)

image-20201107184823648.png

Exceptions属性

列举出方法中可能抛出的检查异常(Checked Exception),也就是方法声明throws关键字后面的列举异常

image-20201107185136111.png

LineNumberTable属性

描述Java源码行号与字节码指令行号(字节码偏移量)对应关系

SourceFile属性

记录生成此Class文件的源码名称

StackMapTable属性

虚拟机类加载验证阶段的字节码验证时,不需要再检验了,只需要查看StackMapTable属性中的记录是否合法

编译阶段将一系列的验证类型结果记录在StackMapTable属性中

image-20201107185712220.png

ConstantValue

在类加载的准备阶段,为静态变量(常量)赋值

只有类变量才有这个属性

实例变量的赋值: 在实例构造器

类变量的赋值: 在类构造器 或 带有ConstantValue属性在类加载的准备阶段

如果类变量被final修饰(此时该变量是一个常量),且该变量数据类型是基本类型或字符串,就会生成ConstantValue属性,该属性指向常量池中要赋值的常量,在类加载的准备阶段,直接把在常量池中ConstantValue指向的常量赋值给该变量

image-20201107191419341

总结所有属性
属性名作用
Code方法体内的代码经过编译后变为字节码指令存储在Code属性中
Exceptions列举出方法可能抛出的检查异常(Checked Exception)
LineNumberTableJava源码行号与字节码偏移量(字节码行号)对应关系
LocalVariableTableJava源码定义的局部变量与栈帧中局部变量表中的变量对应关系(局部变量名称,描述符,局部变量槽位置,局部变量作用范围等)
LocalVariableTypeTableLocalVariableTable相似,只是把LocalVariableTable的描述符换成了字段的特征签名(完成对泛型的描述)
SourceFile记录生成这个Class文件的源码文件名称
SourceDebugExtension用于存储额外的代码调式信息
ConstantValue在类加载的准备阶段,为静态变量(常量)赋值
InnerClasses记录内部类与宿主类之间的关系
Deprecated用于表示某个字段,方法或类已弃用 (可以用注解@deprecated表示)
Synthetic用于表示某字段或方法不是由Java源代码生成的,而是由编译器自行添加的
StackMapTable虚拟机类加载验证阶段的字节码验证时,不需要再检验了,只需要查看StackMapTable属性中的记录是否合法
Signature记录泛型签名信息
BootstrapMethods保存动态调用(invokeeddynamic)指令引用的引导方法限定符
MethodParameters记录方法的各个形参名称与信息

javap解析Class文件

关于javac

javac xx.java 编译Java源文件,不会生成对应的局部变量表

javac -g xx.java 编译Java源文件,生成对应的局部变量表

idea中编译Java源文件使用的是javac -g

关于javap

image-20210513195725462.png

常用

javap -v 基本上可以反汇编出Class文件中的很多信息(常量池,字段集合,方法集合...)

但是它不会显示私有字段或方法的信息,所以可以使用javap -v -p

详解javap -v -p

 public class JavapTest {
     private int a = 1;
     float b = 2.1F;
     protected double c = 3.5;
     public  int d = 10;
 ​
     private void test(int i){
         i+=1;
         System.out.println(i);
     }
 ​
     public void test1(){
         String s = "test1";
         System.out.println(s);
     }
 }

image-20210513200417243.png

image-20210513200532661.png

image-20210513200946912.png

最后(不要白嫖,一键三连求求拉~)

本篇文章笔记以及案例被收入 gitee-StudyJava、 github-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

本文由博客一文多发平台 OpenWrite 发布!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

webpack配置杂记

1、热更新 安装webpack-dev-server : npm i webpack-dev-server -D webpack.config.js配置 module.exports {// 其他配置...,// 热更新配置devServer: {host: "localhost",port: 3000,}, } 2、入口entry:使用相对路径们也就是webpack程序运行的路径&am…

Qt应用软件【协议篇】MQTT官方源码编译安装

文章目录 QT官方代码选择对应的版本Qt Creator编译代码代码下载与编译安装mqtt命令行方式编译与安装代码示例QT官方代码 https://github.com/qt/qtmqtt/tree/5.15.2 选择对应的版本 我们可以在github上切换分支,切换到我们需要的版本上 Qt Creator编译代码 代码下载与编译…

win10编译openjdk源码

上篇文章作者在ubuntu系统上实践完成openjdk源码的编译,但是平常使用更多的是window系统,ubuntu上编译出来JDK无法再windows上使用。所以作者又花费了很长时间在windows系统上完成openjdk源码的编译,陆续花费一个月的时间终于完成了编译。 本…

2024牛客寒假算法基础集训营5 -- EF soyorin的数组操作

题目大意: 思路解析: 我们可以发现偶数情况下,我们可以无限做 k n的操作,这样一定会让数组变为非降序数组。 但是奇数情况下,最后一个数没有办法发生变化,所以我们只能统计怎样在保证i--n为非降序情况下最…

解决IntelliJ IDEA 2023版本创建Spring项目时Java只能选择17或21的问题

问题描述: 当使用IntelliJ IDEA2023版本中Spring Initializr新建Spring项目时,即使JDK配置项为1.8,Java配置项仍然只能选17或21. 在JDK为1.8版本情况下,Java选择17或21,点击NEXT按钮,则会弹窗提示SDK不支持…

ChatGPT丨“成像光谱遥感技术中的AI革命:ChatGPT应用指南“

遥感技术主要通过卫星和飞机从远处观察和测量我们的环境,是理解和监测地球物理、化学和生物系统的基石。ChatGPT是由OpenAI开发的最先进的语言模型,在理解和生成人类语言方面表现出了非凡的能力。本文重点介绍ChatGPT在遥感中的应用,人工智能…

ClickHouse--11--ClickHouse API操作

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1.Java 读写 ClickHouse API1.1 首先需要加入 maven 依赖1.2 Java 读取 ClickHouse 集群表数据JDBC--01--简介 ClickHouse java代码 1.3 Java 向 ClickHouse 表中写…

高校学科竞赛平台|基于springboot高校学科竞赛平台设计与实现(源码+数据库+文档)

高校学科竞赛平台目录 目录 基于springboot高校学科竞赛平台设计与实现 一、前言 二、系统功能设计 三、系统实现 1、竞赛题库管理 2、竞赛信息管理 3、晋级名单管理 4、往年成绩管理 5、参赛申请管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最…

typescript 索引签名类型

ts索引类型简介 在TypeScript中,索引签名类型(Index Signature Type)是一种特殊的类型,它定义了对象中键的类型以及相应的值的类型。通过使用索引签名类型,我们可以表示一个对象,该对象的键可以是任意类型…

Android全新UI框架之常用ComposeUI组件

在Compose中,每个组件都是一个带有Composable注解的函数,被称为Composable。Compose已经预置了很多基于MD设计规范的Composable组件。 在布局方面,Compose提供了Column、Row、Box三种布局组件(感觉跟flutter差不多),类似于传统视图…

《Python 语音转换简易速速上手小册》第5章 音频数据处理(2024 最新版)

文章目录 5.1 音频数据的基本处理5.1.1 基础知识5.1.2 主要案例:音频剪辑工具案例介绍案例 Demo案例分析 5.1.3 扩展案例 1:自动音量调节器案例介绍案例 Demo案例分析 5.1.4 扩展案例 2:语音识别预处理案例介绍案例 Demo案例分析 5.2 使用 Py…

LLM 模型融合实践指南:低成本构建高性能语言模型

编者按:随着大语言模型技术的快速发展,模型融合成为一种低成本但高性能的模型构建新途径。本文作者 Maxime Labonne 利用 mergekit 库探索了四种模型融合方法:SLERP、TIES、DARE和passthrough。通过配置示例和案例分析,作者详细阐…

开启智能互动新纪元——ChatGPT提示词工程的引领力

目录 提示词工程的引领力 高效利用ChatGPT提示词方法 提示词工程的引领力 近年来,随着人工智能技术的迅猛发展,ChatGPT提示词工程正逐渐崭露头角,为智能互动注入了新的活力。这一技术的引入,使得人机交流更加流畅、贴近用户需求&…

S-35390A计时芯片介绍及开发方案

计时芯片 S-35390A芯片是计时芯片,一般用来计算时间。低功耗,宽电压,受温度影响小,适用于很多电路。它有一个问题,不阻止用户设置不存在的时间,设置进去之后计时或者闹钟定时会出错。 规格书阅读 首先我…

推荐几款项目经理常用的项目管理软件

随着科技的发展和项目需求,项目管理工具成为了确保工作顺利进行的关键。市场上有许多优秀的免费项目管理工具,它们功能强大、易于使用,并可以帮助团队更有效地规划、组织、执行和监控项目。以下是几款深受项目经理欢迎,好用且免费…

【转载】企业资产收集与脆弱性检查工具

简介 云图极速版是针对拥有攻击面管理需求的用户打造的 SaaS 应用,致力于协助用户管理互联网资产攻击面的 SaaS 化订阅服务产品。可实现对备案域名、子域名、IP、端口、服务、网站、漏洞、安全风险等场景进行周期性监控,支持多维度分析攻击面。利用可视化…

uni-app 开发调试自动打开手机屏幕大小界面(Aidex移动端开发项目)

上效果: 下载Aidex的移动端项目并打开: 若依-ruoyi-AiDex-Uniapp: 若依-Ruoyi APP 移动解决方案,基于uniappuView封装的一套基础模版,开箱即用,免费开源,一份代码多终端适配,支持H5、支付宝小程…

基于机器学习的青藏高原高寒沼泽湿地蒸散发插补研究_王秀英_2022

基于机器学习的青藏高原高寒沼泽湿地蒸散发插补研究_王秀英_2022 摘要关键词 1 材料和方法1.1 研究区概况与数据来源1.2 研究方法 2 结果和分析2.1 蒸散发通量观测数据缺省状况2.2 蒸散发与气象因子的相关性分析2.3 不同气象因子输入组合下各模型算法精度对比2.4 随机森林回归模…

【统计分析数学模型】聚类分析

【统计分析数学模型】聚类分析 一、聚类分析1. 基本原理2. 距离的度量(1)变量的测量尺度(2)距离(3)R语言计算距离 三、聚类方法1. 系统聚类法2. K均值法 三、示例1. Q型聚类(1)问题描…

springboot集成JWT实现token权限认证

vuespringboot登录与注册功能的实现 注&#xff1a;对于JWT的学习&#xff0c;首先要完成注册和登录的功能&#xff0c;本篇博客是基于上述博客的进阶学习&#xff0c;代码页也是在原有的基础上进行扩展 ①在pom.xml添加依赖 <!-- JWT --> <dependency><grou…
最新文章