JVM工作原理与实战(三):字节码文件的组成

专栏导航

JVM工作原理与实战

RabbitMQ入门指南

从零开始了解大数据


目录

专栏导航

前言

一、基础信息

1.Magic魔数

2.主副版本号

3.其他信息

二、常量池

1.案例解析

三、方法

1.方法介绍

2.案例解析

四、字段

五、属性

总结


前言

JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了字节码文件的基础信息、常量池、方法、字段、属性等内容。


一、基础信息

字节码文件的基础信息包括魔数、字节码文件对应的Java版本号、访问标识(public final等等)、父类和接口内容。

1.Magic魔数

文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改,不影响文件的内容。软件使用文件的头几个字节(文件头)去校验文件的类型,如果软件不支持该种类型就会出错。在Java字节码文件中,将文件头称为magic魔数

文件类型字节数文件头
JPEG (jpg)3FFD8FF
PNG (png)489504E47(文件尾也有要求)
bmp2424D
XML (xml)53C3F786D6C
AVI (avi)441564920
Java字节码文件 (.class)4CAFEBABE

通过NotePad++使用十六进制插件查看class文件:

2.主副版本号

版本号用于标识字节码文件的版本。它包括主版本号和副版本号。主版本号表示编译字节码文件的JDK版本,而副版本号则用于标识不同版本的字节码文件。通过比较字节码文件的主版本号和运行时的JDK版本,可以判断两者是否兼容。

JDK1.0-1.1使用了 45.0-45.3,JDK1.2是46之后每升级一个大版本就加1。1.2之后大版本号计算方法为主版本号 - 44,比如主版本号52就是JDK8。

3.其他信息

访问标识:在Java字节码文件中用于描述类的访问权限和特性。它包括public、private、protected和默认(无标识)等访问级别,以及final、abstract、interface等修饰符。这些标识确定了类的可见性和行为特性,影响着类的使用和继承。

类、父类、接口索引:在字节码文件中,父类和接口的内容通过索引值来表示。这些索引值指向类或接口在常量池中的位置,以便在运行时能够找到它们的相关信息。通过这些索引值,JVM可以在运行时加载并链接所需的类和接口,从而正确执行程序。

二、常量池

常量池是字节码文件中的一个重要组成部分,主要用于存储程序中的常量值,如字符串常量、类或接口名、字段名等。常量池的主要作用是避免相同的内容在字节码文件中重复定义,从而节省空间

在字节码指令中,可以通过常量池中的编号引用相应的常量值。每个常量在常量池中都有一个唯一的编号,编号从1开始。通过这些编号,字节码指令可以快速地定位到常量池中的数据,从而实现高效的数据访问。在字节码指令中引用常量池的过程称为符号引用。通过符号引用来替代实际的数据值,可以在运行时动态地解析和加载相应的数据,提高程序的灵活性和可维护性。

1.案例解析

案例一:

案例代码:

public class ConstantPoolTest {
    public static final String a1 = "This is a test";
    public static final String a2 = "This is a test";
    public static void main(String[] args) {
        ConstantPoolTest constantPoolTest = new ConstantPoolTest();
    }
}

查看字段常量值索引(a1和a2),指向cp_info #8:

进入常量池cp info #8,看到字符串文本内容在cp_info #27:

 进入常量池cp_info #27,可以看到字符串文本内容:

在上面的示例中,字符串常量"This is a test"在常量池中只存储一次。在字节码指令中,可以通过常量池中的编号来引用这两个常量。因此,常量池避免了相同内容的重复定义,节省了存储空间。

案例二:

案例代码:

public class ConstantPoolTest2 {
    public static final String a1 = "abc";
    public static final String a2 = "abc";
    public static final String abc = "abc";
    public static void main(String[] args) {
        ConstantPoolTest2 constantPoolTest = new ConstantPoolTest2();
    }
}

查看字段常量值索引,指向cp_info #8:

 进入常量池cp info #8,看到字符串文本内容在cp_info #10:

 进入常量池cp_info #10,可以看到字符串文本内容:

查看字段abc名称所在常量池,指向cp_info #10:

三、方法

1.方法介绍

在JVM字节码文件中,方法部分是核心,它包含了程序执行的具体指令。这些指令是以字节码的形式存在的,是Java源代码的编译结果。

  • 字节码指令:字节码中的方法区域是存放字节码指令的核心位置,字节码指令的内容存放在方法的Code属性中。
  • 操作数栈:操作数栈在字节码指令执行中起到关键的作用。它是一个后进先出(LIFO)的数据结构,用于临时存储数据。几乎所有的字节码指令都会用到操作数栈,无论是从栈顶弹出数据,还是将数据压入栈中。
  • 局部变量表:局部变量表是存放方法中定义的局部变量的位置。每个方法在JVM中都有一个关联的局部变量表,这个表定义了方法的参数和在方法体内部声明的局部变量。局部变量表中的每个条目都包含一个变量的名称、类型和其在方法中的偏移量。这个偏移量表示该变量在方法栈帧中的位置。
  • 局部变量表数组:局部变量表数组是存放这些局部变量表的数组。每一个方法对应一个局部变量表,该表记录了该方法的所有局部变量的信息,包括它们的名称、类型和偏移量等。这些信息对于JVM在运行时解析字节码和执行相应的操作非常重要。

右键查看JVM规范:

 JVM规范:

2.案例解析

案例一:

案例代码:

public class Demo1 {
    public static void main(String[] args) {
        int i=0;
        i = i++;
    }
}

 查看方法的字节码信息:

 字节码信息解析:

iconst_0将0放入操作数栈
istore_1从操作数栈取出放入局部变量表1号位置
iload_1从局部变量表1号位置加载数据到操作数栈
iinc 1 by 1在局部变量表1号位置增加1
istore_1将操作数栈中的值保存到局部变量表
return方法结束,返回

案例二:

案例代码:

public class Demo2 {
    public static void main(String[] args) {
        int i = 0;
        int j = i + 1;
    }
}

 查看方法的字节码信息:

  字节码信息解析:

iconst_0将常量0放入操作数栈
istore_1从操作数栈取出放入局部变量表1号位置
iload_1将局部变量表1中的数据放入操作数栈
iconst_1将常量1放入操作数栈
iadd将操作数栈顶部的两个数据进行累加,结果放入栈中
istore_2从操作数栈取出放入局部变量表2号位置
return方法结束,返回

四、字段

在JVM字节码文件中,字段部分包含了当前类或接口声明的字段信息。这些字段包括类的成员变量、静态变量、常量等。字段信息在类的字节码文件中被组织为一个字段表,每个字段在表中都有一个唯一的字段表条目。

五、属性

在JVM字节码文件中,属性部分包含了描述类或接口的各种元数据信息。这些属性提供了关于类或接口的附加信息,用于支持某些JVM特性和工具。

常见的属性:

  • 源码的文件名:这个属性提供了类的源文件名,可以帮助调试和错误跟踪。它允许开发人员在运行时与源代码对应,这对于理解和调试代码非常有用。
  • 内部类的列表:如果一个类包含内部类或嵌套类,那么这个属性将列出所有的内部类和嵌套类。这对于解析和执行嵌套类非常关键。
  • 注解:注解是一种提供元数据的方法,可以用于标记代码中的特定元素。在字节码文件中,注解被表示为属性,提供了关于类、方法、字段等的额外信息。
  • 签名:这个属性提供了关于类、方法或字段的签名信息,包括它们的名称和类型。这对于验证类型和调用方法非常重要。
  • 其他属性:还有其他一些属性,如行号表、本地变量表等,这些属性用于支持调试和其他高级功能。


总结

JVM是Java程序的运行环境,负责字节码解释、内存管理、安全保障、多线程支持、性能监控和跨平台运行。本文主要介绍了字节码文件的基础信息、常量池、方法、字段、属性等内容,希望对大家有所帮助。

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

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

相关文章

【致远OA】获取指定人员的协同已办列表

接口说明 按人员编码获取所有待办事项(V6.0接口更新:不在传入ticket,改为传memberId人员ID) 兼容版本 since V7.0 请求方式 V6.0之前http请求方式:GET http://ip:port/seeyon/rest/affairs/done 如 http://127.0.0.1/seeyon/…

Builder建造者模式(对象创建)

Builder 链接:建造者模式实例代码 解析 目的 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这 个复杂对象的各个部分经常面临着剧烈的变化&…

深入理解C#中的隐式类型转换

深入理解C#中的隐式类型转换 在C#中,类型转换可以是显式的或隐式的。理解这些转换的工作原理对于编写高效、可维护的代码至关重要。本文将深入探讨C#中的隐式类型转换,特别关注赋值操作符()在隐式转换中的角色,并对比C…

FL Studio 21最新版本for mac 21.2.2.3740中文解锁版2024最新图文安装教程

FL Studio 21最新版本for mac 21.2.0.3740中文解锁版是最新强大的音乐制作工具。它可以与所有类型的音乐一起创作出令人惊叹的音乐。它提供了一个非常简单且用户友好的集成开发环境(IDE)来工作。这个完整的音乐工作站是由比利时公司 Image-Line 开发的。…

三种方式在ASP.NET Core中实现代理功能请求获取数据的接口(以请求百度统计数据接口为例)

一、定义请求数据属性 TargetUrl参数是目标接口的URL,RequestDataArray参数是要发送的请求数据列表 //定义属性:TargetUrl参数是目标接口的URL,RequestDataArray参数是要发送的请求数据列表public class ToResponseBody{[JsonPropertyName("Target…

安装 Node.js、npm

安装 nodejs 安装Node.js的最简单的方法是通过软件包管理器。 Node.js官网:https://nodejs.org/en/download/ cd /usr/local/src/wget -c https://nodejs.org/dist/v18.16.0/node-v18.16.0-linux-x64.tar.xz xz -d node-v18.16.0-linux-x64.tar.xz tar -xf node…

使用react+vite开发项目时候,部署上线后刷新页面无法访问解决办法

说一下我这边的环境和使用的路由模式:vitereactBrowserRouter路由模式,所以如果你和我一样的话,可以试试我的这种解决办法,我是将项目打包后直接丢到服务器上的目录里面,然后配置nginx直接访问根目录。 我的nginx配置…

Android 模拟器检测

文章目录 普遍检测代码如下:推荐模拟器检测方法:设备信息检测代码:蓝牙检测代码:光传感器检测代码:CPU检测代码: 最近看到某客户端有一个检测模拟器的方法,我正常手机结果被判断是模拟器了&…

Python 自学(一) 之语言基础

目录 0. 前言 1. 声明python解释器 2. 变量的类型 type() id() P35 3. 类型转换 str() P37 4. 换行 r"" P40 5. 常用类型转换函数 P41 6. 特殊的运算符 // ** P42 7. 特殊的比较运算符 0 < a <100 P45 8. 函数输入 input() P51 9. print…

Windows使用IIS服务搭建WebDAV站点结合内网穿透公网访问

文章目录 1. 安装IIS必要WebDav组件2. 客户端测试3. cpolar内网穿透3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访问测试 4. 安装Raidrive客户端4.1 连接WebDav服务器4.2 连接成功4.2 连接成功总结&#xff1a; 自己用Windows Server搭建了家用NAS主机&…

基于mediapipe的人体姿态估计模型——没有GPU依然速度飞起

关于人体姿态检测模型,我们前期也介绍过了很多相关的模型,比如基于Yolo-NAS的姿态检测以及基于YOLOv8的人体姿态检测,而人体姿态估计一直是计算机视觉任务中比较重要的一个模型。但是基于YOLO系列的人体姿态检测模型需要较大的算力,且很难在CPU模型上快速的运行。 基于medi…

【漏洞复现】OpenSSH ProxyCommand命令注入漏洞(CVE-2023-51385)

文章目录 前言一、漏洞背景二、漏洞详情三、影响范围四、漏洞验证 前言 OpenSSH存在命令注入漏洞&#xff08;CVE-2023-51385&#xff09;&#xff0c;攻击者可利用该漏洞注入恶意Shell字符导致命令注入。 一、漏洞背景 OpenSSH 是 SSH &#xff08;Secure SHell&#xff09…

经典目标检测YOLO系列(一)复现YOLOV1(3)正样本的匹配及损失函数的实现

经典目标检测YOLO系列(一)复现YOLOV1(3)正样本的匹配及损失函数的实现 之前&#xff0c;我们依据《YOLO目标检测》(ISBN:9787115627094)一书&#xff0c;提出了新的YOLOV1架构&#xff0c;并解决前向推理过程中的两个问题&#xff0c;继续按照此书进行YOLOV1的复现。 经典目标…

Qt(三):udp组播的发送与接收

1. 创建UDP套接字 使用QUdpSocket类创建一个UDP套接字。 udpSendnew QUdpSocket(this);udpRecenew QUdpSocket(this); 2. 绑定套接字 绑定套接字到一个本地地址和端口。可以使用bind()函数来完成。 如果要在组播中发送数据&#xff0c;可以将套接字绑定到一个通配符地址&#…

m1芯片电脑上的paragon15如何安装激活 m1芯片电脑上ntfs for mac如何安装

Paragon NTFS软件在M1芯片电脑上安装之后&#xff0c;最后一步会让我们“允许加载第三方内核扩展”&#xff0c;具体如下图所示。 图1&#xff1a;允许加载第三方内核扩展 按照图中提示“单击此处“&#xff0c;然后打开安全与隐私。接下来依次点击小锁标志进行解锁&#xff0c…

Abstract Factory抽象工厂模式(对象创建)

抽象工厂模式&#xff1a;Abstract Factory 链接&#xff1a;抽象工厂模式实例代码 解析 目的 在软件系统中&#xff0c;经常面临着“一系列相互依赖的对象工作”&#xff1b;同时&#xff0c;由于需求的变化&#xff0c;往往存在更多系列对象的创建工作。 如何应对这种变化…

EBDP:解锁大数据的奥秘✨

大数据时代已经来临&#xff0c;你是否也想掌握这门“显学”&#xff1f;&#x1f31f; EBDP&#xff0c;这个让众多专业人士趋之若鹜的认证&#xff0c;究竟有何魅力&#xff1f;今天就带你一探究竟&#xff01; &#x1f31f;EBDP&#xff1a;大数据的“敲门砖”&#x1faa…

无线路由器的五种工作模式:

1.Router&#xff0c;即无线路由模式&#xff0c;这也是我们最常用的一种工作方式&#xff0c;一般家里宽带连接&#xff0c;将宽带猫连接在无线路由的WAN口上&#xff0c;然后做拨号帐号设置&#xff0c;就用这个模式即可。 在Router&#xff08;无线路由&#xff09;模式下&a…

预售价80万元的ET9,能否拯救蔚来【不断恶化】的财务业绩?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 发布新车型 12月23日&#xff0c;蔚来&#xff08;NIO&#xff09;的创始人李斌在西安NIO DAY上发布了蔚来自成立以来售价最高的车型--ET9。 据猛兽财经了解&#xff0c;ET9定位于行政旗舰&#xff0c;预售价为80万元&…

【C语言】Windows上用GTK写GUI程序

要使用GTK开发一个Windows图形用户界面程序&#xff0c;需要首先设置GTK开发环境。这通常包括安装GTK库和它的依赖&#xff0c;以及配置编译器和工具链。可以选择使用纯C语言和GTK库或者使用支持GTK绑定的其他语言&#xff0c;如Python、C或Rust。 1. 安装GTK开发库 在Window…