JVM学习-Class文件结构①

字节码文件的跨平台性
Java语言:跨平台的语言(Write Once,Run Anywhere)
  • 当Java源代码编译成字节码后,如果想在不同平台上运行,则无须再次编译
  • 这上优势不再那么吸引人,Python,PHP,Ruby,Lisp等有强大的解释器
  • 跨平台似乎已经成为一门语言必选的特性
Java虚拟机:跨语言的平台
  • Java虚拟机不和包括Java在内的任何语言绑定,它只与“Class文件”这种特定的二进制格式文件关联,无论使用何种语言进行软件开发,只要能将源文件编译成正确的Class文件,那么这种语言就可以在Java虚拟机上执行,统一而强大的Class文件结构,是Java虚拟机的基石和桥梁。请添加图片描述
  • 所有的JVM全部遵守Java虚拟机规范,字节码文件可以在各种JVM上执行
前端编译器
  • 负责将符合Java语法规范的Java代码编译成符合JVM规范的字节码
  • javac是最常用的前端编译器
  • javac编译器将Java源码编译为一个有效的字节码文件过程经历4步,分别是词法分析、语法分析、语义解析以及生成字节码
    请添加图片描述
Oracle JDK软件包括两部分内容
  • 一部分将Java源代码编译成Java虚拟机的指令集的编译器
  • 另一部分是用于实现Java虚拟机的运行时环境
public class IntegerTest {
    public static void main(String[] args) {
        Integer x = 5;
        int y = 5;
        System.out.println(x == y);

        Integer i1 = 5;
        Integer i2 = 5;
        System.out.println(i1 == i2);

        Integer i3 = 128;
        Integer i4 = 128;
        System.out.println(i3 == i4);
    }
}
//执行结果
true
true
false
//查看字节码
 0 iconst_5
 1 invokestatic #2 <java/lang/Integer.valueOf>   //给Integer x进行赋值
 4 astore_1
 5 iconst_5
 6 istore_2
 7 getstatic #3 <java/lang/System.out>
10 aload_1
11 invokevirtual #4 <java/lang/Integer.intValue>  //对Integer x进行拆箱操作
14 iload_2
15 if_icmpne 22 (+7)
18 iconst_1
19 goto 23 (+4)
22 iconst_0
23 invokevirtual #5 <java/io/PrintStream.println>
26 iconst_5
27 invokestatic #2 <java/lang/Integer.valueOf>
30 astore_3
31 iconst_5
32 invokestatic #2 <java/lang/Integer.valueOf>
35 astore 4
37 getstatic #3 <java/lang/System.out>
40 aload_3
41 aload 4
43 if_acmpne 50 (+7)
46 iconst_1
47 goto 51 (+4)
50 iconst_0
51 invokevirtual #5 <java/io/PrintStream.println>
54 sipush 128
57 invokestatic #2 <java/lang/Integer.valueOf>
60 astore 5
62 sipush 128
65 invokestatic #2 <java/lang/Integer.valueOf>
68 astore 6
70 getstatic #3 <java/lang/System.out>
73 aload 5
75 aload 6
77 if_acmpne 84 (+7)
80 iconst_1
81 goto 85 (+4)
84 iconst_0
85 invokevirtual #5 <java/io/PrintStream.println>
88 return


/**
 * 成员变量赋值过程:①默认初始化②显式初始化③构造器初始化④有了对象后,可以通过对象.属性的方式对成员变量赋值
 */
class Father {
    int x = 10;

    public Father() {
        this.print();
        x = 20;
    }
    public void print() {
        System.out.println("Father.x = " + x);
    }
}
class Son extends Father {
    int x = 30;

    public Son() {
        this.print();
        x = 40;
    }
    public void print() {
        System.out.println("Son.x = " + x);
    }
}
public class SonTest {
    public static void main(String[] args) {
        Father f = new Son();
        System.out.println(f.x);
    }
}
//执行结果
Son.x = 0
Son.x = 30
20
Class文件
  • 字节码文件里是什么?
  • 源代码经过编译器编译生成一个字节码文件,字节码是一种二进制的类文件,它的内容是JVM指令,不像C,C++经由编译器直接生成机器码
  • 什么是字节码指令(byte code)
  • Java虚拟机的指令由一个字节长度,代表某种特定操作含义的操作码以及跟随其后的零至多个代表此操作所需参数的操作数所构成,虚拟机中指令并不包含操作数,只有一个操作码
    在这里插入图片描述
  • 如何解读供虚拟机解释执行的二进制字节码
  • ①通过NotePad++中安装一个HEX-Editor插件,或使用BinaryViewer
    在这里插入图片描述
  • ②使用javap指令:jdk自带反解析工具
C:\Users\Administrator\IdeaProjects\jvm\target\classes\com\chapter09>javap -v -p IntegerTest.class
  • ③使用IDEA插件:jclasslib或jclasslib bytecode viewer客户端
Class文件结构
//class文件结构相应信息都使用下面代码编译为字节码进行
public class Demo {
    private int num = 1;

    public int add() {
        num += 2;
        return num;
    }
}
  • class类的本质
    任何一个Class文件都对应着唯一一个类或接口的定义信息,但反过来说,Class文件实际上它并不一定以磁盘文件的形式存在,Class文件是一组以字节为基础单位的二进制流
  • class文件格式
  • Class的结构不像XML等描述语言,由于没有分隔符,所以其中的数据项,无论是字节顺序还是数量,都被严格限定,哪个字节代表什么含义,长度多少,先后顺序如何,都不允许改变
  • Class文件格式采用一种类似于C语言结构体的方式进行数据存储,包含两种数据类型:无符号数和表
  • 无符号数属于基本的数据类型,以u1,u2,u4,u8来分别代表1字节,2字节,4字节和8字节无符号数,无符号数可以用来描述数字、索引引用、数量值或者按UTF8编码构成的字符串值
  • 表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以_info结尾,表用于描述有层次关系的复合结构数据,整个Class文件本质上就是一张表,由于表没有固定长度,所以通常会在其前面 加上个数说明
  • class文件结构描述
  • Class文件的结构并不是一成不变的,随着Java虚拟机的不断发展,总是不可避免地会对Class文件结构做出一些调整,但是其基本结构和框架是非常稳定的
  • 魔数
  • Class文件版本
  • 常量池
  • 访问标志
  • 类索引、父类索引、接口索引集合
  • 字段表集合
  • 方法表集合
  • 属性表集合
    在这里插入图片描述
魔数(Magic Number)
  • 每个Class文件开头的4个字节的无符号整数称为魔数
  • 它的唯一作用是确定文件是否为一个能被虚拟机接受的有效合法的Class文件,即魔数是Class文件的标识符
  • 魔数值固定为0xCAFEBABE,不会改变
  • 如果一个Class文件不以oxCAFEBABE开头,虚拟机在进行文件校验的时候就会直接抛出以下错误:
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1885430635 in class file Demo
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access$100(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
  • 使用魔数而不是扩展名来进行识别主要是基于安全方面的考虑,因为文件扩展名可以随意地更改
Class文件版本号
  • 紧接着魔数的4个字节存储的是Class文件的版本号,同样4个字节,第5、6字节所代表的含义就是编译的副版本号minor_version,第7、8字节就是编译的主版本号major_version
  • 它们共同构成了class文件的格式版本号,譬如某个Class文件的主版本号为M,副版本号为m,那么这个Class文件的格式版本号就确定为M.m
  • 版本号和Java编译器的对应关系统如下
    在这里插入图片描述
  • Java版本号从45开始,JDK1.1之后的每个JDK大版本发布主版本号向上加1
  • 不同版本的Java编译器的Class文件对应的版本是不一样的,目前,高版本的Java虚拟机可以执行由低版本编译器生成的Class文件,但是低版本的Java虚拟机不能执行高版本编译器生成的Class文件,否则JVM会抛出java.lang.UnsupportedClassVersionError异常
  • 在实际应用中,由于开发环境和生产环境的不同,可能导致该问题的发生,因此,需要在开发时,注意开发编译JDK版本和生产环境是否一致
  • 虚拟机JDK版本为1.k(k >= 2)时,对应的class文件格式版本号的范围为45 - (44 + k.0)
常量池
  • 常量池是Class文件中最为丰富的区域之一,常量池对于Class文件中的字段和方法解析也有着至关重要的作用

  • 随着Java虚拟机的不断发展,常量内容日渐丰富,常量池是整个Class文件的基石
    在这里插入图片描述

  • 在版本号之后,是常量池的数量,以及若干个常量池表项

  • 常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项u2类型的无符号数,代表常量池容量计数值(constant_pool_count),与Java中语言习惯不一样的是,这个容量计数是从1而不是0开始的
    在这里插入图片描述

  • 由上表可见,Class文件使用了一个前置的容量计数器(constant_pool_count)加若十个连续的数据项(constant_pool)的形式来描述常量池内容,我们把一系列连续常量池数据称为常量池集合

  • 常量池表项中,用于存放编译时期生成的各种字面量和符号引用,这部分加载后进入方法区的运行时常量池中存放

常量池计数器
  • 由于常量池的数量不固定,时长时短,需要两个字节表示常量池容量计数值
  • 常量池容量计数值:从1开始,表示常量池中有多少项常量,即constant_pool_count = 1表示常量池中有0个常量项
    在这里插入图片描述

其值0x0016,掐指一算,是22
注:实际上只有21项常量,索引范围1-21,常量池是从1开始的

常量池
  • constant_poo是一种表结构,以1-constant_pool_count - 1索引,表明后面有多少个常量项
  • 常量池主要存放两大类常量:字面量(Literal)和符号引用(Symbolic Reference)
  • 它包含了class文件结构及子结构中引用的所有字符串常量、类或接口名、字段名和其他常量,常量池中的每一项具备相同的特征,第1个字节作为类型标记,用于确定该项的格式,这个字节称为tag byte(标记字节、标签字节)
    在这里插入图片描述
字面量和符号引用

在这里插入图片描述

  • 全限定名
  • com/chapter09/Demo这个是类的全限定名,仅把包名的".“替换为”/“,为了使连续的多个全限定名之间不产生混淆,在使用时最后一般会加入一个”;"表示全限定名结束
  • 简单名称
  • 简单名称是没有类型和类修饰的方法或者字段名称,上面例子中的类的add()方法和num字段的简单名称分别为add和num
  • 描述符
  • 描述符的作用用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值,根据描述符规则,基本数据类型(byte,char,double,float,int,long,short,boolean)以及代表无返回值的void类型都用一个大写字符来表示,而对象类型用字符L加对象的全限定名来表示
    在这里插入图片描述
    注:虚拟机在加载Class文件时才会进行动态链接,Class文件中不会保存各个方法和字段的最终内存布局信息,因此,这些字段和方法的符号引用不经过转换是无法直接被虚拟机使用的,当虚拟机运行时,需要从常量池中获得对应的符号引用,再在类加载过程中的解析阶段将其替换为直接引用,并翻译到具体的内存地址中
  • 符号引用:以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可,符号引用与虚拟机实现内存布局无关,引用的目标并不一定已经加载到了内存中
  • 直接引用:可以直接指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。直接引用是与虚拟机实现的内存布局相关的,同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般不会相同,如果有了直接引用,那说明引用的目标必定已经在于内存之中了。

在这里插入图片描述
注:常量池:可以理解为Class文件之中的资源仓库,它是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项之一
常量池中为何要包含这么多内容
Java代码在进行Javac编译的时候,并不像C和C++那样有“连接”这一步骤,而是在虚拟机加载Class文件的时候进行动态链接,在Class文件中不会保存各个方法、字段的最终内存布局信息,因此这些字段、方法的符号引用不经过运行期转换无法得到真正的内存地址,也就无法直接被虚拟机使用,当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。

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

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

相关文章

【iOS开发】—— KVC

【iOS开发】—— KVC 一. KVC的定义key和keyPath的区别用法&#xff1a; 批量复制操作字典模型相互转化KVC的其他方法 KVC原理赋值原理取值原理 一. KVC的定义 KVC&#xff08;Key-value coding&#xff09;键值编码&#xff0c;就是指iOS的开发中&#xff0c;可以允许开发者通…

C#--SVG矢量图画法示例

1.代码示例 <Viewbox Grid.Column"1" Grid.ColumnSpan"1" Grid.RowSpan"1" ><Path Name"ValveShape" Stroke"Black" Data"M 50,0 L 150,200 L 50,200 L 150,0 Z" Width"200" Height"…

文件系统--inode

文章目录 概述认识磁盘了解磁盘的存储结构对磁盘的存储结构进行逻辑抽象 操作系统对磁盘的使用宏观认识细节认识再谈目录再谈文件的增删 概述 文件有很多&#xff0c;但是被打开的文件很少&#xff0c;这些没有被打开的文件在磁盘中&#xff0c;这就叫做磁盘文件。每次先打开一…

【JavaEE初阶】网络初识|局域网和广域网|交换机和路由器|IP地址|端口号

&#x1f4a1;推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击跳转到网站】 关键概念 1.局域网LAN和广域网WAN &#xff08;1&#xff09;局域⽹&#xff0c;即Local Area Network&#xff0…

一文扫尽Nas常用Docker软件

NAS&#xff08;Network Attached Storage&#xff0c;网络附加存储&#xff09;设备上的Docker软件选择取决于您的具体需求和用途。以下是一些NAS上常用的Docker软件推荐&#xff1a; Docker管理工具&#xff1a; Watchtower&#xff1a;它可以自动更新Docker容器中的镜像&…

浮点型比较大小

浮点数的存储形式 浮点数按照在内存中所占字节数和数值范围&#xff0c;可以分为浮点型&#xff0c;双精度浮点型和长双浮点型数。 代码&#xff1a; printf("lgn:%e \n", pow(exp(1), 100));printf("lgn:%f ", pow(exp(1), 100));输出结果&#xff1a; …

Vue | 自定义组件双向绑定基础用法

Vue | 自定义组件双向绑定基础用法 vue 中&#xff0c;由于单向数据流&#xff0c;常规的父子组件属性更新&#xff0c;需要 在父组件绑定相应属性&#xff0c;再绑定相应事件&#xff0c;事件里去做更新的操作&#xff0c;利用语法糖 可以减少绑定事件的操作。 这里就简单的梳…

ROS | 激光雷达包格式

ros激光雷达包格式&#xff1a; C实现获取雷达数据 &#xff1a; C语言获取雷达数据&#xff1a; Python语言获取雷达数据&#xff1a; python不需要编译&#xff0c;但是需要给它一些权限 chmod x lidar_node.py(当前的文件名字&#xff09; C实现雷达避障&#xff1a; python…

网络模型-NQA与网络协议联动

一、NQA定义 网络质量分析NQA(Network QualityAnalysis)是一种实时的网络性能探测和统计技术&#xff0c;可以对响应时间、网络抖动、丢包率等网络信息进行统计。NOA能够实时监视网络0oS&#xff0c;在网络发生故障时进行有效的故障诊断和定位。 部署IPv4静态路由与BFD…

SpringBoo+vue3整合讯飞星火3.5通过webscoket实现聊天功能(全网首发)附带展示效果

API版本&#xff1a;Spring Boot 整合讯飞星火3.5通过接口Api接口实现聊天功能&#xff08;首发&#xff09;复制粘贴即可使用&#xff0c;后续更新WebSocket实现聊天功能_讯飞星火web聊天-CSDN博客https://blog.csdn.net/qq_53722480/article/details/138865508?csdn_share_t…

QTextEdit将多个字符作为一个整体,不可单独修改

考虑一个问题&#xff0c;QTextEdit如何实现类似微信和QQ聊天输入框中的“xxx”效果&#xff0c;其内容作为一个整体&#xff0c;以突出颜色显示&#xff0c;并且不可以单独编辑修改&#xff0c;只能整体删除修改。 突出颜色显示有很多方式可以实现&#xff0c;例如 通过setT…

【回忆版】数据科学思维与大数据智能分析 2024考试

填空&#xff08;18分&#xff09;18个 1.对数变换对大数值的范围进行压缩&#xff0c;对小数值的范围进行扩展 2.提取出大量高频率项与低频率项相关联的虚假模式&#xff0c;即交叉支持&#xff08;cross-support&#xff09;模式 3.信息论中&#xff08;&#xff09; 4.几种…

vivado 设计连接性

设计连接性 IP集成商提供设计师协助&#xff0c;帮助您完成连接过程 设计。图3显示了MHS的一个示例&#xff0c;图4显示了设计帮助 可在IP集成商中获得 地址映射 在XPS中&#xff0c;无论主机访问从机IP&#xff0c;每个从机都有相同的地址。IP integrator为基于master的寻址提…

Fitting Parameterized Three-Dimensional Models to Images

摘要 基于模型的识别和运动跟踪依赖于解决投影和模型参数&#xff0c;使其最佳适应匹配的2D图像特征的3D模型的能力。本文将当前的参数求解方法扩展到处理具有任意曲面和任意数量的内部参数&#xff08;表示关节、可变尺寸或表面变形&#xff09;的对象。开发了数值稳定化方法…

games 101 作业4

games 101 作业4 题目题解作业答案 题目 Bzier 曲线是一种用于计算机图形学的参数曲线。在本次作业中&#xff0c;你需要实 现 de Casteljau 算法来绘制由 4 个控制点表示的 Bzier 曲线 (当你正确实现该 算法时&#xff0c;你可以支持绘制由更多点来控制的 Bzier 曲线)。 你需…

鸿蒙ArkUI-X平台差异化:【运行态差异化(@ohos.deviceInfo)】

平台差异化 简介 跨平台使用场景是一套ArkTS代码运行在多个终端设备上&#xff0c;如Android、iOS、OpenHarmony&#xff08;含基于OpenHarmony发行的商业版&#xff0c;如HarmonyOS Next&#xff09;。当不同平台业务逻辑不同&#xff0c;或使用了不支持跨平台的API&#xf…

python纯脚本搬砖DNF之深度学习,工作室适用

声明&#xff1a; 本文章仅作学习交流使用,对产生的任何影响&#xff0c;本人概不负责. 转载请注明出处:https://editor.csdn.net/md?articleId103674748 主要功能 脚本已初步完成&#xff0c;可以上机实战了 1.搬砖研究所、海伯伦&#xff08;持续更新中&#xff09; 2.自…

【知识拓展】LocalTunnel-高性价比的内网穿透工具(2)

前言 上一篇通过ngrok进行内网穿透&#xff0c;有几个问题&#xff1a; ①需要注册&#xff0c;而且注册需要科学上网&#xff0c;相对麻烦 ②安装配置相对麻烦&#xff0c;authtoekn有限制 上述相对&#xff0c;指的是在非生产环境中做一个简单内网穿透&#xff0c;相对于…

C++系列-C/C++内存管理方式

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” C/C内存分布 在这篇文章开始之前&#xff0c;我们先以一道题目来进行引入&#xff1a; int glovalvar 1; static int staticGlovalvar 1; void Test() {static int staticva…

内网安全--域渗透准备知识

目录 知识点&#xff1a; 0x01 0x02 0x03 系列点&#xff1a; Linux主机信息收集 windows主机信息收集 知识点&#xff1a; 0、域产生原因 1、内网域的区别 2、如何判断在域内 3、域内常见信息收集 4、域内自动化工具收集 -局域网&工作组&域环境区别 -域…