第六章 类文件结构

1、无关性的基石

  • 各种不同平台的虚拟机与所有平台都统一使用程序存储格式——字节码是构成平台无关的基石。
  • 实现语言无关性的基础仍然是虚拟机和字节码存储格式,Java虚拟机不和包括Java在内的任何语言绑定只能与class文件这种特定的二进制文件格式所关联。
  • class文件包含了Java虚拟机指令集和符号表以及若干其他辅助信息。

2、class文件结构

概述:

  • class文件是一组以八位字节为基础的二进制流,各个数据项目严格按照顺序紧凑的排列在class文件中。
  • class文件格式采用一种类似于C语言结构的伪数据结构来存储数据,这种伪数据结构包含两种数据类型无符号和表。
  • 无符号数属于基本数据类型,从u1、u2、u4、u8来分别表示一个字节、两个字节、四个字节、八个字节的无符号数。无符号数可以用来描述数字、索引、引用7数量值或者按照utf-8编码构成字符串值。
  • 表是由多个无符号或者其他表作为数据项构成的复合数据类型。所有的表都习惯性地以“_info”结尾。表示描述有层次关系的复合结构的数据,整个class文件本质就是一张表。

魔数:

  • 每个class文件的头四位为魔数,作用是确定这个文件是否是一个能被虚拟机引用接受的class文件,class文件的魔数值是0xCAFEBABE。

class文件的版本:

  • 紧接着魔数的四个字节存储的是class文件的版本号,第5和第6个字节是次版本号,第7和第8个是主版本号。

常量池:

  • 紧接着主版本号的是常量池入口,常量池可以理解为class文件中的资源仓库,它是class文件结构中与其他项目关联的最多的数据类型,也是占有class文件空间最大的数据项目之一,同时它是class文件第一个出现的表类型数据。
  • 由于常量池的常量数值不固定,所以在常量池的入口需要放置一项u2类型的数据代表常量池容量计数值,计数是从一开始的。
  • 常量池主要存放两大常量,字面量和符号引用,字面量比较接近于Java语言层面的常量概念,如文字字符串,声明为final的常量池等。
  • 符号引用包括类和接口的全限定名,字段的名称和描述符,方法的名称和描述符。
  • 常量池中每一项常量都是一个表,根据标志位来确定项目类型。
    package com.ecut.clazz;
    
    public class TestClass {
    private int m; public int inc() {
    return m + 1;
    }
    }

    字节码文件对应的16进制如下图:

    常量容量计数值为22则代表有21个常量,第一个常量的标志位是0x0A,根据下表可知对应的项目类型是CONSTANT_Methodref_info,此类型代表类中方法的符号引用,这个项目类型对应的结构有两个index,第一个index为0x0004为即十进制4,第二个index为0x0012即十进制18。第二个常量是以此类推,这个项目类型为CONSTANT_Fieldref_info,第一个index为0x0003即十进制3,第二个index为0x0013即十进制19。

  • 剩下的常量可以借助class文件字节码的工具javap来输出TestClass.class文件字节码内容。采用javap -verbose TestClass.class命令。

访问标志:

  • 在常量池结束之后,紧接着的两个字节代表访问标志,这个标志用于标识一些类或者接口层次的访问信息,包括是类还是接口,是否为public类型,是否为abstract。具体的标志位以及标志的含义如下表:
  • access_flag中一共有16个标志位可以使用,当前只定义了其中8个,没有使用到的标志位要求一律为0。
  • TestClass被public修饰并且使用了jdk1.2之后的编译器进行了编译,因此它的access_flag标志值应该为100001=0x21。

类索引、父类索引、接口索引:

  • 类索引用于确定表达这个类的全限定名,父类索引用于确定这个类的父类的全限定名,接口索引集合就用于描述这个类实现了那些接口,这些接口按implements语句从左到右排列在接口缩影集合中。

字段表集合:

  • 用于描述接口或类中声明的变量。字段包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。
  • 字段集合不会列出从超类中或者父类接口中继承而来的字段,但有可能列出原本没有的字段,如在内部类中为了保持外部类的访问性会加入外部类的实例字段。
  • 字段包含信息:字段的作用域(public、private、protected),是实例变量还是类变量(static修饰符),可变性(final)、并发性(volatile修饰符,是否强制从主内存读写)、可否被序列化(transient修饰符),字段数据类型(基本类型、对象、数组),字段名称。
  • 字段修饰符放在access_flag项目中,它包含两项name_index和descript_index,他们都是对常量池的引用,分别代表字段的简单名称和字段的描述符。
  • 字段表结构如下图所示:
  • 结合之前的常量池中的常量可知类索引为 com/ecut/clazz/TestClass,父类索引为 java/lang/Object。TestClass包含一个被private修饰的int 类型的m。                                                 

方法表集合:

  • 方法表集合包括访问标志、名称索引、描述符索引、属性集合。如果父类方法在子类方法中没有被重写,方法表集合中不会有来自父类的方法信息。
  • 方法表结构如下图:

属性表集合:

  • 在class文件中,字段表方法表都可以携带自己的属性表集合,以用于描述某些场景专有的信息。
  • 属性集合的结构如下图:
  • 结合常量池对文件进行分析可得,方法容量为2包含了两个方法,第一个方法时public修饰void init,该方法包含了一个属性code,code操作数栈最大值为1.第二个方法时public修饰的int inc()该方法也包含了一个属性code。

  • Exception属性列举出方法中可能抛出的异常,也就是方法描述时在throws关键字后面列出的异常。
  • LineNumberTable属性用于描述Java源码行号和字节码行号之间的对应关系。
  • LocalVariableTable属性用来描述栈帧中局部变量与Java源码中定义的变量之间的关系。
  • SourceFile属性用来记录生成这个class源码文件名称。

3、字节码指令

概述:

  • Java虚拟机的指令由一个字节长度的,代表着某中特定操作含义的数字(称为操作码)以及跟随其后的零至多个代表此操作所需参数(称为操作数)而构成。
  • Java虚拟机采用面向操作数栈的架构所以大多数指令都不包含操作数只有一个操作码。
  • 在Java虚拟机的指令集中大多数指令都包含了其操作锁对应的数据类型信息。

加载和存储指令:

  • 加载存储指令用来将数据在栈帧中的局部变量和操作数栈之间来回传输。
  • 将一个局部变量加载到操作数栈iload。
  • 将一个数值从操作数栈中存储到局部变量表istore。
  • 将一个常量加载到操作数栈bipush。
  • 扩充局部变量表的访问索引的指令wide。

运算或算法指令:

  • 运算或算法指令用于对两个操作数栈上的值进行某中特定的运算,并把结果重新存入操作数栈的栈顶。

类型转换指令:

  • 类型转换指令可以将两种不同的数值类型进行相互转换,这种转换操作一般用于实现用户代码中的显示类型转换操作。
  • int——》long——》float——》double。

对象创建和访问指令:

  • 虽然类实例和数组都是对象但是使用不同的指令来完成创建。
  • 创建类实例的指令 new。
  • 创建数组的指令 newarray。
  • 访问类字段和实例字段 putfield 、getfield、getstatic。

操作数栈管理指令:

  • 将操作数栈的栈顶一个元素出栈pop。
  • 将栈顶两个数值交换swap。

控制转移指令:

  • 在有条件或者无条件的修改PC寄存器的值。
  • 条件分支ifea、iflt。
  • 复合条件分支lookupswich。
  • 无条件goto 。

方法调用和返回指令:

  • 方法调用指令和返回值无关,而方法返回指令是根据返回值类型来区分的。
  • invokevirtual用于调用对象的实例方法。
  • invokestatic用于调用类方法。

异常处理指令:

  • 在Java程序中显示抛出异常的操作都有athrow指令来完成。
  • Java虚拟规范还规定许多运行时异常会在其他指令检测到异常时自动抛出。

同步指令:

  • Java虚拟机可以支持方法级的同步和方法内部一段指令序列的同步,这两种同步结构都是使用管程(Monitor)来支持的。

推荐博客链接:

https://blog.csdn.net/u010349169/column/info/jvm-principle

转载请于明显处标明出处:

https://www.cnblogs.com/AmyZheng/p/10537013.html

《深入理解Java虚拟机》读书笔记五的更多相关文章

  1. 【鸟哥的Linux私房菜】笔记1

    Linux是什么 从操作系统与cpu架构关系到linux  Richard Mathew Stallman GPL 关于GNU计划 Linux的发展 Linux的核心版本 Linux的特色 Linux ...

  2. 【鸟哥的Linux私房菜】笔记3

    正确地开机 最好不要使用root账号登陆!GNOME图形界面 View items as a list X WindowShell 文本交互界面bash是Shell的名称,Linux的默认壳程序就是b ...

  3. 【鸟哥的Linux私房菜】笔记2

    Linux的应用 学习资源整理 安装记录 >< 1.Linux的应用: 网络服务器 数据库 学术机构的高效运算任务 嵌入式系统 ... 2.挂载与磁盘分区 学习资源整理 学习 1.书上的网 ...

  4. 《鸟哥的Linux私房菜》笔记——02. 关于Linux

    Unix 历史 1969年以前:伟大的梦想--Bell, MIT 与 GE 的「Multics」系统 1969年:Ken Thompson 的小型 file server system 1973年:U ...

  5. 《鸟哥的Linux私房菜》笔记——03. 磁盘分区

    Everything is a file. 常见硬件对应于 Linux 下的文件(/dev目录下) 装置 装置在Linux内的档名 SCSI/SATA/U盘硬盘机 /dev/sd[a-p] U盘 /d ...

  6. 鸟哥的linux私房菜学习笔记 __ 命令与文件的搜寻

    连续输入两次[tab]按键就能够知道使用者有多少命令可以下达.那你知不知道这些命令的完整档名放在哪里?举例来说,ls 这个常用的命令放在哪里呢? 就透过 which 或 type 来找寻吧! 范例一: ...

  7. 【鸟哥的Linux私房菜】笔记

    操作系统核心的功能! 驱动程序与操作系统的关系 2. [计算机组成之组件] 3.CPU实际要处理的数据完全来自于主存储器,这是一个很重要的概念! 4.CPU是整个计算机系统最重要的部分,那么目前世界上 ...

  8. 《鸟哥的Linux私房菜》笔记——04. 简单命令行

    键入命令 [dmtsai@study ~]$ command [-options] parameter1 parameter2 ... 指令 選項 參數(1) 參數(2) 注意:有时也可以使用 + 放 ...

  9. 鸟哥的Linux私房菜学习笔记——文件权限与目录配置

    Linux的文件权限和目录配置 在linux中的每个用户必需属于一个组,不能独立于组外.在linux中每个文件有所有者.所在组.其它组的概念. (1)所有者 一般为文件的创建者,谁创建了该文件,就是天 ...

  10. 鸟哥的Linux私房菜学习笔记(1)

    2014/10/29 1.档案的权限管理分为三个部分: 拥有者.群组.其他 2.ls -al 命令可以看到档案的详细信息 3.档案的属性中由十个部分构成 第一个部分是档案类型 -代表档案.d代表文件夹 ...

随机推荐

  1. Your idea evaluation has expired. Your session will be limited to 30 minutes

    今天打开idea,出现了上面的话,试了网上的很多办法,获取注册码的那个方法是最常见的,那个网站现在不提供注册码了. ----两种方法-----**1)把提示框的x点掉,会自动打开idea**按最开始安 ...

  2. LeetCode刷题专题

    1. https://leetcode-cn.com/problems/container-with-most-water/ 思想:左右边界  i,j   向中间收敛 ,左右夹逼 方法一: 一维数组的 ...

  3. NetCore文件上传校验返回未授权401,文件仍然执行上传操作,要如何解决呢

    这是代码:https://files.cnblogs.com/files/suterfo/NetCoreTestPro.rar 运行步骤: 一.使用Visual Studio2017打开项目,并F5运 ...

  4. 腾讯云nginx配置https

    给腾讯nginx服务器配置https, 之前申请https配置后直接给node配置了,还没有用nginx. 按照 https://cloud.tencent.com/document/product/ ...

  5. python学习随笔2:python判断和循环

    1.if-else _username = 'heyue' _password = ' username = input("username:") password = input ...

  6. .net core 中如何读取 appsettings.json 相关配置

    appsettings.json如下 { "Logging": { "LogLevel": { "Default": "Debug ...

  7. laravel手动数组分页

    laravel文档中已经有写如何自己使用分页类去分页了,但没有详细说明. 如果你想手动创建分页实例并且最终得到一个数组类型的结果,可以根据需求来创建 IlluminatePaginationPagin ...

  8. Java虚拟内存(栈、堆)

    一.java虚拟的内存可以分为几种 1. 第一种 栈(stack) 栈的特点 1.1 栈描述的是方法执行的内存模型,每个方法都被调用都会创建一个栈(存储局部变量.操作数. 方法出口等) 1.2 JVM ...

  9. 复习babel

    对babel进行复习

  10. 备战2020年金三银四,看这一篇面试文章就够了(合适各级Java人员)

    本文不是原创.为整理所得!但是内容是很干货的!我看了也有帮助.做个分享. 企业开始上班,就意味着大批量的招聘需求正在路上.在即将到来的金三银四跳槽面试季,提前祝贺大家拿到大厂offer.前程似锦.前程 ...