【JVM学习笔记】字节码文件结构
https://www.cnblogs.com/heben/p/11468285.html 比这篇笔记更好一点
新建一个Java类
- package com.learn.jvm;
- public class MyTest1 {
- private int a = 1;
- public MyTest1() {
- }
- public int getA() {
- return this.a;
- }
- public void setA(int a) {
- this.a = a;
- }
- }
在控制台使用javap -c进行反解析
- D:\workspace-learn\common-learn\learn-classloader\target\classes\com\learn\jvm>javap -c MyTest1
- 警告: 二进制文件MyTest1包含com.learn.jvm.MyTest1
- Compiled from "MyTest1.java"
- public class com.learn.jvm.MyTest1 {
- public com.learn.jvm.MyTest1();
- Code:
- 0: aload_0
- 1: invokespecial #1 // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iconst_1
- 6: putfield #2 // Field a:I
- 9: return
- public int getA();
- Code:
- 0: aload_0
- 1: getfield #2 // Field a:I
- 4: ireturn
- public void setA(int);
- Code:
- 0: aload_0
- 1: iload_1
- 2: putfield #2 // Field a:I
- 5: return
- }
在控制台使用javap -verbose进行反解析
- D:\workspace-learn\common-learn\learn-classloader\target\classes\com\learn\jvm>javap -verbose MyTest1
- 警告: 二进制文件MyTest1包含com.learn.jvm.MyTest1
- Classfile /D:/workspace-learn/common-learn/learn-classloader/target/classes/com/learn/jvm/MyTest1.class
- Last modified 2019-9-4; size 473 bytes
- MD5 checksum 8dc78fb3801af3d26bc3befec9b7c5ed
- Compiled from "MyTest1.java"
- public class com.learn.jvm.MyTest1
- SourceFile: "MyTest1.java"
- minor version: 0
- major version: 51
- flags: ACC_PUBLIC, ACC_SUPER
- Constant pool:
- #1 = Methodref #4.#20 // java/lang/Object."<init>":()V
- #2 = Fieldref #3.#21 // com/learn/jvm/MyTest1.a:I
- #3 = Class #22 // com/learn/jvm/MyTest1
- #4 = Class #23 // java/lang/Object
- #5 = Utf8 a
- #6 = Utf8 I
- #7 = Utf8 <init>
- #8 = Utf8 ()V
- #9 = Utf8 Code
- #10 = Utf8 LineNumberTable
- #11 = Utf8 LocalVariableTable
- #12 = Utf8 this
- #13 = Utf8 Lcom/learn/jvm/MyTest1;
- #14 = Utf8 getA
- #15 = Utf8 ()I
- #16 = Utf8 setA
- #17 = Utf8 (I)V
- #18 = Utf8 SourceFile
- #19 = Utf8 MyTest1.java
- #20 = NameAndType #7:#8 // "<init>":()V
- #21 = NameAndType #5:#6 // a:I
- #22 = Utf8 com/learn/jvm/MyTest1
- #23 = Utf8 java/lang/Object
- {
- public com.learn.jvm.MyTest1();
- flags: ACC_PUBLIC
- Code:
- stack=2, locals=1, args_size=1
- 0: aload_0
- 1: invokespecial #1 // Method java/lang/Object."<init>":()V
- 4: aload_0
- 5: iconst_1
- 6: putfield #2 // Field a:I
- 9: return
- LineNumberTable:
- line 8: 0
- line 9: 4
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 10 0 this Lcom/learn/jvm/MyTest1;
- public int getA();
- flags: ACC_PUBLIC
- Code:
- stack=1, locals=1, args_size=1
- 0: aload_0
- 1: getfield #2 // Field a:I
- 4: ireturn
- LineNumberTable:
- line 12: 0
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 5 0 this Lcom/learn/jvm/MyTest1;
- public void setA(int);
- flags: ACC_PUBLIC
- Code:
- stack=2, locals=2, args_size=2
- 0: aload_0
- 1: iload_1
- 2: putfield #2 // Field a:I
- 5: return
- LineNumberTable:
- line 16: 0
- line 17: 5
- LocalVariableTable:
- Start Length Slot Name Signature
- 0 6 0 this Lcom/learn/jvm/MyTest1;
- 0 6 1 a I
- }
能够看到,字节码文件中是有常量池 Constant pool
注意,以上反解析得到的并不是真正的class文件的二进制内容,而是解析的结果,可以通过其他相关工具对真正的二进制内容进行查看,将会看到类似下图的结果,其中左边是真正的二进制内容
上图左侧是按照单字节分组显示的,比如CA是一个字节,FE是一个字节。(注:一个字节是8位,而一个16进制数占4位,所以一个字节是两个十六进制数组成的)
要点:
- 使用java -verbose 命令分析一个字节码文件时,将会分析该字节码文件的魔数、版本号、常量池、类信息、类的构造方法、类中的方法信息、类变量与成员变量等信息
- 魔数:所有.class字节码文件的前四个字节都是魔数,,魔数值为固定值:0xCAFEBABE
- 魔数之后的4个字节代码版本号,前2个字节代表次版本号(minor version),后2个字节代表主版本号(major version),以上图为例,次版本号为0,主版本号为52,所以,该文件的版本号是1.8.0
- 常量池(constant pool):紧接着主版本号之后的就是常量池入口。一个Java类定义的很多信息都是由常量池来维护和描述的,可以将常量池看作是Class文件的资源仓库,比如说Java类中定义的方法与变量信息,都是存储在常量池中。常量池中主要存储两类常量:字面量与符号应用。字面量如文本字符串,Java中声明为final的常量值等,而符号引用如类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符等
- 常量池的总体结构:Java类所对应的常量池主要由“常量池数量”与“常量池数组”这两部分共同构成。常量池数量紧跟在主版本号后面(也就是第9个字节开始),占据2个字节;常量池数组则紧跟在常量池数量之后。常量池数组与一般的数组不同的是,常量池数组中不同的原素的类型、结构都是不同的,长度当然也就不同,但是,每一种元素的第一个数据都是一个u1类型,该字节是个标志位,占据1个字节。JVM在解析常量池时,会根据这个u1类型来获取元素的具体类型。以上图为例,第9到第10个字节连起来时 0018,即十进制数字的24,意即后面有24个常量。值得注意的是,常量池数组中元素的个数 = 常量池数 - 1(其中0暂时不使用),目的是满足某些常量池索引值的数据在特定情况下需要表达“不引用任何一个常量池”的含义;根本原因在于,索引为0也是一个常量(保留常量),只不过它不位于常量池数组(也叫常量表)中,这个常量就对应null值,所以常量池的索引从1而非0开始。以上图为例显示有24个常量,但是根据 java -verbose的输出结果,显示只有23个常量。
- 在JVM规范种,每个变量/字段都有描述信息,描述信息的主要作用是描述字段的数据类型、方法的参数列表(包括数量、类型与顺序)与返回值。根据描述符规则,基本数据类型和代表无返回值的void类型都用一个大写字符来表示,而对象类型则使用字符L加对象的全限定名称来表示。为了压缩字节码文件的体积,对于基本数据类型,JVM都只使用一个大写字母,如下所示:B - byte ,C - char,D - double,F - float, I - int,J - long,S - short,Z - boolean,V - void,L - 对象类型,如Ljava/lang/String;
- 对于数组类型来说,每一个维度使用一个前置的[来表示,如int[]被记录为[I,String[][]被记录为[[Ljava/lang/String;
- 用描述符来描述方法时,按照先参数列表,后返回值的顺序来描述。参数列表按照参数的严格顺序放在一组()之类,如方法String getRealNameByIdAndName(int id, String name),表示为(I,Ljava/lang/String;)Ljava/lang/String;
附《Class文件结构中常量池中11种数据类型的结构总表》
U1表示长度为一个字节,U2表示长度为2个字节。上面的表中描述了11种数据类型的结构,其实在jdk1.7之后又增加了3种(CONSTANT_MethodHandle_info, CONSTANT_MethodType_info以及CONSTANT_InvokeDynamic_info)。所以加上上面的11种,一共是14种
然后对常量数组种的元素逐一分析:
第一个常量,组成如下:
U1 类型的 0A 对应值为10的 CONSTANT_Methodref_info
U2 类型的 00 04,换算成十进制是4
U2 类型的 00 14,换算成十进制是20
Class字节码中有两种数据类型
- 字节数据直接量:这是基本的数据类型。共细分为u1,u2,u4,u8四种,分别代表连续的1个字节,2个字节,4个字节,8个字节组成的整体数据。
- 表(数组):表是由多个基本数据或其他表,按照既定顺序组成的大的数据集合。表是有结构的,它的结构体现在:组成表的成分所在的位置和顺序都是已经严格定义号的。
Access_Flag访问标志
访问标志信息包括该Class文件是类还是接口,是否被定义为public,是否是abstract,如果是类,是否被声明为final
上图缺少了0x0002代表 ACC_PRIVATE
在本文的例子中,访问标志的值是 00 21,对应于上图就是 ACC_PUBLIC | ACC_SUPER (即这两者的并集)
字段表集合
字段表用于描述类和接口中声明的变量。这里的字段包含了类级别变量以及实例变量,但是不包括方法内部声明的局部变量。
本文例子中,字段表集合是0001打头的,代表有1个字段。后面的内容就是该字段的描述信息
下图看起来更清晰
其中 attribute_info结构如下
这个工具比javap -verbose更全面一些,有idea插件可供下载
LineNumberTable的结构:
其他:
在Java代码的每个非静态方法中都可以使用this指针,实际上从字节码角度来看,this是作为每个方法的第一个参数传递给了方法来实现的。
【JVM学习笔记】字节码文件结构的更多相关文章
- JVM学习笔记——字节码指令
JVM学习笔记——字节码指令 字节码 0与 1是计算机仅能识别的信号,经过0和1的不同组合产生了数字之上的操作.另外,通过不同的组合亦产生了各种字符.同样,可以通过不同的组合产生不同的机器指令.在不同 ...
- JVM学习笔记之class文件结构【七】
一.概念 1.1 无符号数: 以 u1.u2.u3.u4.u8 代表 1 个字节,2 个字节.4 个字节.8 个字节的无符号数.无符号数可以描述数字,索引引用.数量值和按照 UTF-8 编码构成的字符 ...
- JVM学习笔记——类加载和字节码技术篇
JVM学习笔记--类加载和字节码技术篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的类加载和字节码技术部分 我们会分为以下几部分进行介绍: 类文件结构 字节码指令 编译期处理 类 ...
- JVM学习笔记:字节码执行引擎
JVM学习笔记:字节码执行引擎 移步大神贴:http://rednaxelafx.iteye.com/blog/492667
- JVM学习笔记-第六章-类文件结构
JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...
- JVM基础系列第5讲:字节码文件结构
温馨提示:此篇文章长达两万字,图片50多张,内容非常多,建议收藏后再看. 前面我们说到 Java 虚拟机使用字节码实现了跨平台的愿景,无论什么系统,我们都可以使用 Java 虚拟机解释执行字节码文件. ...
- <JVM中篇:字节码与类的加载篇>01-Class字节码文件结构
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- JVM学习笔记:虚拟机的类加载机制
JVM类加载机制分两部分来总结: (1)类加载过程 (2)类加载器 一.JVM类加载过程 类的加载过程:加载 →连接(验证 → 准备 → 解析)→ 初始化. 类的生命周期:加载 →连接(验证 → 准备 ...
- java之jvm学习笔记三(Class文件检验器)
java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...
随机推荐
- linux下top命令的使用
top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器 视图参数含义 top视图分为两部分:操作系统资源概况信息和进程信息.首先分析资源 ...
- 推荐几款好用的Chrome插件
'工欲善其事,必先利其器'.优秀的开发者不仅体现在其在技术方面的精通,还体现在其对各种开发工具的充分了解与使用,这会让其开发效率事半功倍.作为一个前端开发者,平时主要是跟浏览器打交道,Chrome浏览 ...
- HTML table 边框双线变单线
table{border-collapse:collapse;border-spacing:0;border-left:1px solid #888;border-top:1px solid #888 ...
- C语言编译错误:Variably modified array at file scope
今天在编译一段C源程序时,遇到编译错误提示 error: variably modified 'data' at file scope.原因在于代码头部有这样几行: +; int data[maxsi ...
- JavaScript属性名和属性值
㈠属性名 var obj = new Object(); 向对象中添加属性 ⑴属性名: - 对象的属性名不强制要求遵守标识符的规范 什么乱七八糟的名 ...
- CSS测试题Ⅰ
1.CSS 指的是? A. Computer Style Sheets B. Cascading Style Sheets C. Creative Style Sheets D. Colorf ...
- 蓝桥 log大侠
标题:Log大侠 atm参加了速算训练班,经过刻苦修炼,对以2为底的对数算得飞快,人称Log大侠. 一天,Log大侠的好友 drd 有一些整数序列需要变换,Log大侠正好施展法力... 变换的规则是: ...
- 理解urllib、urllib2及requests区别及运用
urllib and urllib2 区别 –博主提示:下面的是python2中的用法,python3需要做出相应修改. urllib和urllib2模块都做与请求URL相关的操作,但他们提供不同的功 ...
- AcWing:177. 噩梦(bfs)
给定一张N*M的地图,地图中有1个男孩,1个女孩和2个鬼. 字符“.”表示道路,字符“X”表示墙,字符“M”表示男孩的位置,字符“G”表示女孩的位置,字符“Z”表示鬼的位置. 男孩每秒可以移动3个单位 ...
- cookies ,session,localstorage讲解
一 .cookie (1)简介 因为HTTP协议是无状态的,服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现.在典型的网上购物场景中,用户浏览了几个页面,买了一盒饼干和两饮料.最 ...