JVM学习-Class文件结构①

news2024/11/19 7:32:36
字节码文件的跨平台性
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文件中不会保存各个方法、字段的最终内存布局信息,因此这些字段、方法的符号引用不经过运行期转换无法得到真正的内存地址,也就无法直接被虚拟机使用,当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。

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

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

相关文章

c语言:模拟strlen(三种方法)最全版本

1.计数的方法 #include <stdio.h> #include <assert.h> int my_strlen(const char * str)//const的使用优化 {int count0;assert(str)while(*str){count;str;}return count; } 2.用指针的方法&#xff08;指针-指针&#xff09; #include <stdio.h> #incl…

ML307R OpenCPU 数据保存文件系统fs使用

一、函数介绍 二、实现数据保存 三、代码下载地址 一、函数介绍 以下是cm_fs.h里面的函数介绍 /*** brief 文件指针定位** param [in] fd 文件描述符* param [in] offset 指针偏移量* param [in] base 偏移起始点&#xff0c;CM_FS_SEEK_SET&#xff1a;文件开头 CM_FS…

零基础学Java第二十三天之网络编程Ⅱ

1. InetAddress类 用来表示主机的信息 练习&#xff1a; C:\Windows\system32\drivers\etc\ hosts 一个主机可以放多个个人网站 www.baidu.com/14.215.177.37 www.baidu.com/14.215.177.38 www.taobao.com/183.61.241.252 www.taobao.com/121.14.89.253 2. Socket 3.…

vue3和vite实现vue-router4版本路由的配置以及自动生成路由配置

这个是普通的手动路由配置&#xff1a;https://blog.csdn.net/weixin_68658847/article/details/130071101 自动路由配置 创建项目 npm create vitelatest my-vue-app -- --template vue // 或者 yarn create vite my-vue-app --template vue// 安装路由 yarn add vue-route…

WAF几种代理模式详解

WAF简介 WAF的具体作用就是检测web应用中特定的应用&#xff0c;针对web应用的漏洞进行安全防护&#xff0c;阻止如SQL注入&#xff0c;XSS&#xff0c;跨脚本网站攻击等 正向代理 WAF和客户端与网络资源服务器都建立连接&#xff0c;但是WAF 的工作口具有自己的 IP 地址&…

vscode 插件-01基础

翻译 Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code 适用于 VS Code 的中文&#xff08;简体&#xff09;语言包 远程连接 Remote Development Remote Development是vscode的远程编程与调试的插件&#xff0c;使用这个插件可以在很多情况下代替vim…

CentOS 的常见命令

CentOS 是一种广泛使用的 Linux 发行版&#xff0c;特别在服务器环境中。本文将详细介绍 CentOS 中常见的命令&#xff0c;以便帮助用户在操作系统中有效地进行各种操作。下面介绍一下文件和目录操作、用户和权限管理、系统信息查看、软件包管理以及网络配置等方面的命令。 一…

Java 类加载和实例化对象的过程

1. 类加载实例化过程 当我们编写完一个*.java类后。编译器&#xff08;如javac&#xff09;会将其转化为字节码。转化的字节码存储在.class后缀的文件中&#xff08;.class 二进制文件&#xff09;。接下来在类的加载过程中虚拟机JVM利用ClassLoader读取该.class文件将其中的字…

JavaEE初阶多线程 (5)

1.锁的策略 1.1锁的策略是什么 这个锁的策略可以理解为&#xff0c;一种做法&#xff0c;相当于当你遇到锁竞争&#xff0c;加锁解锁&#xff0c;的情况你会怎么做。 乐观锁可以理解为疫情的时候比较乐观就买了最基本的物资&#xff0c; 买的时候非常方便 1.2乐观锁 当效率…

linux的用户管理

新建用户&#xff1a;1.useradd 2.passwd 完成的操作&#xff1a; (1)/etc/passwd添加一行 (2)/etc/shadow添加一行 (3)/etc/group添加一行 (4)创建用户家目录 (5)创建用户邮件文件 例&#xff1a;创建用户jerry&#xff0c;要求: uid:777&am…

Linux系统进程管理

系统进程管理 一、进程概述 1.1 什么是进程&#xff1f;进程管理需要做什么&#xff1f; 进程是已启动的运行实例&#xff0c;进程有以下组成部分&#xff1a; ​ 已分配内存的地址空间 ​ 进程ID ​ 程序的代码 ​ 进程状态 进程管理包括进程调度、中断处理、信号、进程…

基于 vuestic-ui 实战教程

1. 前言简介 Vuestic UI是一个基于开源Vue 3的UI框架。它是一个MIT许可的UI框架&#xff0c;提供了易于配置的现成前端组件&#xff0c;并加快了响应式和快速加载Web界面的开发。它最初于2021年5月由EpicMax发布&#xff0c;这就是今天的Vuestic UI。 官网地址请点击访问 体验…

半年不在csdn写博客,总结一下这半年的学习经历,coderfun的一些碎碎念.

前言 自从自己建站一来&#xff0c;就不在csdn写博客了&#xff0c;但是后来自己的网站因为资金问题不能继续维护下去&#xff0c;所以便放弃了自建博客网站来写博客&#xff0c;等到以后找到稳定&#xff0c;打算满意的工作再来做自己的博客网站。此篇博客用来记录自己在csdn…

SCI审稿结果也可能是剽窃的?Nature重锤:可能只是冰山一角

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 近期&#xff0c;Nature报道了华沙生命科学大学水文学家Mikołaj Piniewski和他的同事们&#xff0c;针对学术界同行评审报告剽窃的调查结果。该团队披露了数十起明显的同行评…

Android单元测试实践

一、基础概念 按照Google官方建议,Android测试体系应该参照测试金字塔架构(如下图所示),App应该包含三类测试(即小型、中型和大型测试)。 图片 小型测试是指单元测试,用于验证应用的行为,一次验证一个类。中型测试是指集成测试,用于验证模块内堆栈级别之间的交互或相…

CHI协议_1

作者&#xff1a;someone链接&#xff1a;https://www.zhihu.com/question/304259901/answer/3455648666来源。 1. AMBA CHI简介 一致性总线接口&#xff08;CHI&#xff09;是AXI一致性扩展&#xff08;ACE&#xff09;协议的演进。它是Arm的AMBA总线的一部分。AMBA是一种免…

【数据结构/C语言】深入理解 双向链表

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;数据结构与算法 在阅读本篇文章之前&#xff0c;您可能需要用到这篇关于单链表详细介绍的文章 【数据结构/C语言】深入理解 单链表…

博客开始使用 Cache Master 缓存插件

明月在给大家推荐 Cache Master 插件的时候&#xff08;可参考【推荐个比较纯正的缓存插件——Cache Master】一文&#xff09;&#xff0c;仅仅是在其他站点上试用了一下&#xff0c;今天明月正式在博客上用上了 Cache Master&#xff0c;没有想到对 Dragon 主题的支持竟然是出…

5月26(信息差)

&#x1f30d; 珠峰登顶“堵车”后冰架断裂 5人坠崖 2人没爬上来&#xff01; 珠峰登顶“堵车”后冰架断裂 5人坠崖 2人没爬上来&#xff01; &#x1f384; Windows 11 Beta 22635.3646 预览版发布&#xff1a;中国大陆地区新增“微软电脑管家”应用 ✨ 成都限购解除即将满…

2024年上半年软件系统架构师考试【回忆版】

文章目录 考试时间考试地点综合知识案例分析1、微服务架构的优点和缺点2、质量属性的6个要素3、分布式锁 Redis的缺点4、MongoDB 存储矢量图的优势 论文回忆版论文一、论单元测试的设计与应用论文二、论大数据模型的设计与应用论文三、论模型驱动的架构设计及应用论文四、论云原…