【java编程】深入浅出JVM(四):类文件结构

news/2024/11/8 11:48:00/文章来源:https://www.cnblogs.com/o-O-oO/p/18534247

原创 菜菜的后端私房菜

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

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

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

一、无关性的基石

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

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

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

字节码是无关性的基石。

平台无关性的基石:

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

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

语言无关性的基石:

Java虚拟机
字节码

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

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

二、Class类文件结构

文件格式存取数据的类型

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

2.1 初识Class文件格式

2.1.1 编写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;}}}

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

每个集合前都有一个计数器来统计集合中元素的数量

2.1.3 Class文件格式的描述


魔数与主次版本号

魔数: 确定这个文件是否为一个能被虚拟机接受的有效Class文件

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

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

常量池

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

    符号引用使用一组符号描述引用(为了定位到目标引用)与虚拟机内存布局无关还是符号引用时目标引用不一定被加载到内存直接引用直接执行目标的指针,相对偏移量或间接定位目标引用的句柄与虚拟机内存布局相关解析直接引用时目标引用已经被加载到内存中
字面量文本字符串被final声明的常量符号引用全限定名方法或字段的简单名称和描述符

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

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

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

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

ACC_PUBLIC:被public修饰

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

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

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

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

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

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

字段表集合:描述类声明的字段

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

    简单名称字段: 没有描述字段类型的名称方法: 没有描述参数列表和返回类型的名称描述符参数列表按照从左到右的顺序写在()中。返回类型写到最后。比如String method(long[],int,String[]) => ([JIL[java.lang.String)Ljava.lang.String在前面先写n个[ 再写标识字符。比如java.lang.Integer[ ] => [Ljava.lang.Integer字段: 描述字段的类型方法: 描述参数列表和返回值描述符字符含义(long,boolean,对象类型是J,Z,L 其他都是首字母大写)

描述符描述n维数组描述符描述方法

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

1、字段表集合不会列出父类或父接口中声明的字段2、只用 简单名称 来确定字段,所以不能有重名字段3、用 简单名称 和 描述符 确定方法,所以方法可以重名(重载)字节码文件 规定 简单名称+描述符相同才是同一个方法但是 Java语法 规定 重载 = 简单名称相同 + 描述符的参数列表不同 + 描述符的返回类型不能不同

方法表集合:描述类声明的方法

与字段表集合类似

属性表集合:用于描述某些场景专有信息

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

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

Code属性

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

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

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

Exceptions属性

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

LineNumberTable属性

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

SourceFile属性

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

StackMapTable属性

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

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

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

只有类变量才有这个属性

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

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

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

总结所有属性


三、javap解析Class文件

关于javac

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

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

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

关于javap

常用

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);}}

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

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

相关文章

HyperWorks实体网格划分

实体网格剖分 在 HyperMesh 中,使用 Solid Map 功能进行实体网格剖分。该面板如下图所示:图 4-4 Solid Map 面板 通过 Solid Map Panel 进行实体网格剖分: • 通过主菜单栏选择 3D 页面 > solid map 。 • 通过下拉式菜单选择 Mesh > create > Solid Map。 Solid Ma…

VS 2022 不支持 .NET Framework 4.5 项目解决办法(Visual Studio 2022)

VS 2022 不支持 .NET Framework 4.5 项目解决办法(Visual Studio 2022) 概述 最近 C# 开发工具 Visual Studio 升级到了 2022,打开速度快了很多,开发体验也舒服很多。只是使用过程中遇到了一个比较尴尬的问题:默认Visual Studio 2022 不再支持安装 .NET Framework 4.5 组件…

新建流程隐藏指定流程(建模+api+ecode)

ecode代码 `// 功能总开关 let enable = true; let list=[]; $.ajax({ type:GET, url:/api/xiangxin/Multiple/HideProcess, success:function(res){ res.data.map((i)=>{ // console.log(lc :, i.lc); list.push(i.lc); }) } }) let pd; //判断是否是新建流程页面 ecodeSDK…

分布式事物传递 NetMQ测试

using NetMQ; using NetMQ.Sockets; using System; using System.Threading; namespace 消息传递库_NetMQ服务端 {internal class Program{public static void Main(){using (var publisher = new PublisherSocket()){// 绑定到一个端口,等待订阅者连接publisher.Bind("t…

Java实现身份证OCR识别API

近年来,随着业务量的不断增加,人工录入方式越来越难以满足高效办理业务的需求,而且越来越多的移动 APP涉及到个人身份证信息的实名认证,为了提高在移动终端上输入身份证信息的速度和准确性,一种可以识别并提取身份证上文字信息的技术接口应运而生,即身份证 OCR 识别 API …

调试优科R750 无线AP

最近项目上用到几个优科的R750设备,头一次整 一头雾水,还是英文太差了。其实官网上有许多手册,也有社区。 先是打了RUCKUS官网上的400电话,全是英文,没有办法找集成商要了销售的微信,他们介绍了一个技术,用微信给我传了一个升级固件(R750-200.9.10.4.233.bl7);后来我…

LeetCode 2544[交替数字和]

LeetCode 2544[交替数字和]题目 链接 LeetCode 2544[交替数字和] 详情实例提示题解 思路 依次求出各位数字,然后进行计算 循环找出各位数字:(循环体如下)将数字对10取余得到对应位数的数字,加入到容器 numVec数字除以10,得到新的数字,此数字是不包含已获取数字的位数 循…

Ubuntu系统下载

推荐LTS长期支持版本 下载地址 Ubuntu Releases至于下边这个网站,不推荐用,很可能下载到beta之类的版本 Index of /releases

人工智能入门

确定性计算,符号主义(早期人工智能) 不确定性计算:建模、机器学习(世界的随机性、不确定性和动态性 - 需要模式识别(学习)的能力,从数据中总结规律)智能即学习。人类的学习,是有类比思维的,得出方法论、哲学;机器的学习,只是在训练特征参数,没有灵性。机器学习常…

iOS-Tagent上新了,iOS17的wda的部署小技巧你get了吗

iOS17以上设备的wda安装小技巧来啦!快来get这个小技巧吧!感兴趣的同学可以戳推文详细阅读~此文章来源于项目官方公众号:“AirtestProject” 版权声明:允许转载,但转载必须保留原链接;请勿用作商业或者非法用途一、前言 之前有很多同学一直在问如何在iOS17的设备上安装wda…

antd Select下拉项数据过多,偶现下拉面板空白

问题 如下,偶现点击选择框,下拉面板空白(数据确定已返回)解决 查看github中的issues发现其他人也有同样的问题,大概是和 virtual list 有关 https://github.com/ant-design/ant-design/issues/26116修改代码如下: <Select...其他属性virtual={false} />

Qt 窗口强制禁用系统阴影(自定义菜单)

解决方法 当只使用Qt::FramelessWindowHint时,不会显示系统阴影,因为自定义菜单一般都会添加Qt::Popup,添加Qt::Popup后系统会默认添加阴影效果。 在添加Qt::Popup后,继续添加Qt::NoDropShadowWindowHint枚举解决。最小复现代码:QDialog *dia = new QDialog();dia->set…