Java字节码方法表与属性表深度剖析
方法表:
在上一次咱们已经分析到了字段信息了,如下:

紧接着就是方法相关的信息了:

而它展开之后的结构为:

所以往后数2个字节,看一下方法的总数:

3个方法,可咱们只定义了两个方法呀:

因为编译器会为我们生成一个默认的构造方法,所以就3个了,那每个方法的具体信息是啥呢?它是一个method_info类型的,如下:

也就是方法表,当然也有它自己的一个结构,下面来看一下:

- access_flags:占用两个字节,表示访问标记。
- name_index:占用两个字节,名字索引,指向的是常量池。
- descriptor_index:占用两个字节,描述索引,指赂的是常量池。
- attributes_count:占用两个字节,属性个数,如果为0,则下面的属性表就不显示了。
- attributes::属性表。
用结构形式来表示:

那按照上面的表先来看第一个方法的访问标记,往后读两个字节:

查看下访问修饰符表,对应于:

表示是一个public的方法,接下来两个字节则表示方法名字索引,走着:

对应常量池:

再往下二个字节则表示描述符索引:

对应常量池:

说明该方法是一个默认构造方法。从javap -verbose中也能对应上:

属性表:
接下来二个字节为属性个数:

表示有一个属性,所以属性表中的个数也为1,而属性表是attribute_info类型,很显然也有它自己的结构,那长啥样呢?

- attribute_name_index:占2个字节,表示属性名字的索引,指向常量池。
- attribute_length:占4个字节,表示属性的长度。
- info[attribute_length]:占1个字节,表示具体的信息。
依照上面的顺序,先数2个字节:

对应常量池:

其实在javap -verbose中也能看到每个方法都有一个Code字样,如下:
Constant pool:
#1 = Methodref #4.#20 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#21 // com/jvm/bytecode/MyTest1.a:I
#3 = Class #22 // com/jvm/bytecode/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/jvm/bytecode/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/jvm/bytecode/MyTest1
#23 = Utf8 java/lang/Object
{
public com.jvm.bytecode.MyTest1();
descriptor: ()V
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 3: 0
line 4: 4
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lcom/jvm/bytecode/MyTest1; public int getA();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field a:I
4: ireturn
LineNumberTable:
line 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/jvm/bytecode/MyTest1; public void setA(int);
descriptor: (I)V
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 11: 0
line 12: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/jvm/bytecode/MyTest1;
0 6 1 a I
}
SourceFile: "MyTest1.java"
那它表示啥意思呢?其实是表示方法执行的代码,指的是:

当然啦在字节码文件中不可能是跟源文件中看到的一样,而是通过了一些助记符进行了处理,如下:

这个在未来进行详细学习的,好,继续来分析属性,接下来4个字节表示属性的长度,如下:

说明属性的长度为56,然后最后一个字节表示info信息,也就是code的具体信息,这块是比较复杂的,下面先来了解一些理论:
- JVM预定义了部分attribute,但是编译器自己也可以实现自己的attribute写入class文件里,供运行时使用。
- 不同的attribute通过attribute_name_index来区分。
其中JVM预定义的attribute为如下表:

Code结构:
这部分东东是比较多的,这次只先对其结构有个初步了解既可,它的作用是保存该方法的结构,如所对应的字节码:

- attribute_length表示attribute所包含的字节数,不包含attribute_name_index和attribute_length字段。
- max_stack表示这个方法运行的任何时刻所能达到的操作数栈的最大深度。
- max_locals表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量。
- code_length表法该方法所包含的字节码的字节数以及具体的指令码。
- 具体的字节码既是该方法被调用时,虚拟机所执行的字节码。
- exception_table:这里存放的是处理异常的信息。
- 第一个exception_table表项由start_pc、end_pc、handler_pc、catch_type组成。
- start_pc和end_pc表示在code数组中的从start_pc到end_pc处(包含start_pc,不包含end_pc)的指令抛出的异常会由这个表项来处理。
- handler_pc表示处理异常的代码的开始处。catch_type表示会被处理的异常类型,它指向常量池里的一个异常类。当catch_type为0时,表示处理所有的异常。
这么多陌生的字段,直接晕掉,木要着急,先有个大概了解,在未来学习中会吃透它的,好,先来回到字节码中继续分析,其中code中属性的长度为56:

接下来2个字节表示max_stack:


再接下来2个字节表示max_locals:


对应javap -verbose:

接下来4个字节表示code的长度:


code_length=10,而此时发现在javap -verbose中貌似木有找到对应的:

那接下来的分析没有了参照就不知道我们自己分析的对不对了,对于学习效果会大打折扣了,此时就得借助于另外一个工具来参照了,该工具为jclasslib,gitbub地址:https://github.com/ingokegel/jclasslib,它显示的信息就会比javap -verbose要详细很多,访问一下官网:

它包含独立的软件和IntelliJ IDEA插件化的方式,所以都装一下,先下载mac安装包:


具体安装就不概述了,装好之后用它来打开我们的字节码文件既可,长这样:

同时可以给IDE装上插件,更加便于分析,如下:

安装好之后,直接就可以在当前打开的java文件中执行这个菜单选项既可:

看到的效果跟独立的软件看到的是一样的,好,下面来用这个新工具来瞅一眼看到的信息:

对比下javap -verbose:

差不多,不过jclasslib工具可以看到JDK的版本,接下来就是常量池:

但实际是只有23个,展开看一下:

对于javap -versbose:

明显要丰富许多,继续往下看:


其中是可以直接点击链到对应的常量池的,如下:


接着就是常量池的信息了:

展开之后,索引都能链接上去,非常之方便:

接着就是接口信息,目前木有接口:

然后就到了字段信息了,目前只有一个字段:

然后再是方法信息,有三个方法:

点击其中一个看一下:

有code信息:
跟javap -versbose是对应上的:


最后是附加信息:

LineNumberTable:这个属性用来表示code数组中的字节码和Java代码行数之间的关系。这个属性可以用来在调试的时候定位代码执行的行数。比如说程序抛异常了,而程序执行的是字节码文件,怎么我们就能看到具体报错在源码中的行数呢,其实就是通过该信息做到的。
而它的结构体为:


跟javap -verbose中是能对应上的:

最后则是类的属性了:


可见jclasslib的结构跟咱们理论上看到的是一模一样的,所以有了它也能让我们在未来学习code这块的结构更加清晰,这是javap -verbose不能达到的。
Java字节码方法表与属性表深度剖析的更多相关文章
- JVM Java字节码方法表与属性
方法表 1.methods_count method_info,前三个字段和field_info一样 2.方法的属性结构 方法中的每个属性都是一个attribut_info结构 JVM定义了部分at ...
- Java字节码方法表与属性表详解
继续跟着上一次[https://www.cnblogs.com/webor2006/p/9502507.html]的那10个代表code的字节分析,如下: 而这些字节其实对应的信息是它: 所以问题就来 ...
- Java字节码方法表结构深度剖析
继续上一次[https://www.cnblogs.com/webor2006/p/9459681.html]的字节码分析,这次来分析一下最为复杂的方法表的信息,如下: 而上一次分析到了属性表的位置在 ...
- 从 HelloWorld 看 Java 字节码文件结构
很多时候,我们都是从代码层面去学习如何编程,却很少去看看一个个 Java 代码背后到底是什么.今天就让我们从一个最简单的 Hello World 开始看一看 Java 的类文件结构. 在开始之前,我们 ...
- 空手套白狼,硬阅java字节码class文件
如下,是一些java字节码也就是原始的class文件,当应用部署到线上之后,我们能够看到的也就是这样的字样了.那么怎样解呢?就让我们一起,来解读解读字节码吧! Offset A B C D E F C ...
- Java字节码 小结
Reference javap 基本使用方法 深入理解java字节码 从Java代码到字节码 Java字节码.class文件案例分析 字节码 核心概念 Class文件是8位字节流,按字节对齐.之所以称 ...
- 轻松看懂Java字节码
java字节码 计算机只认识0和1.这意味着任何语言编写的程序最终都需要经过编译器编译成机器码才能被计算机执行.所以,我们所编写的程序在不同的平台上运行前都要经过重新编译才能被执行. 而Java刚诞生 ...
- 大话+图说:Java字节码指令——只为让你懂
前言 随着Java开发技术不断被推到新的高度,对于Java程序员来讲越来越需要具备对更深入的基础性技术的理解,比如Java字节码指令.不然,可能很难深入理解一些时下的新框架.新技术,盲目一味追新也会越 ...
- @使用javap反编译Java字节码文件
在Sun公司提供的JDK中,就已经内置了Java字节码文件反编译工具javap.exe(位于JDK安装目录的bin文件夹下). 我们可以在dos窗口中使用javap来反汇编指定的Java字节码文件.在 ...
随机推荐
- 使用JavaScript实现量化策略并发执行
本文代码和文章发在FMZ发明者比特币量化交易平台上: 使用JavaScript实现量化策略并发执行--封装Go函数 - 发明者量化 https://www.fmz.com/digest-topic/3 ...
- xml 数组 互相转换方法
public function xmlToArray($xml) { //将XML转为array $array_data = json_decode(json_encode(simplexml_loa ...
- python2.7 升级到 python3.6
1.命令 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel t ...
- 【leetcode算法-简单】53. 最大子序和
[题目描述] 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4],输出: 6解释: ...
- python计算平面的法向-利用协方差矩阵求解特征值和特征向量
Obvious,最小特征值对应的特征向量为平面的法向 这个问题还有个关键是通过python求协方差矩阵的特征值和特征向量,np.linalg.eig()方法直接返回了特征值的向量和特征向量的矩阵 sc ...
- vue-cli webpack打包后加载资源的路径问题
vue项目,访问打包后的项目,输入路径后,页面加载空白.这时会有两类问题,都是路径问题. 1.一个是css,js,ico等文件加载不到,是目录里少了dist 打开页面时一片空白 解决办法: confi ...
- 一个好隐蔽的C/C++代码bug
来自:微博@ruanyf, 一本书上说,下面的 C 语言代码可能会产生无限循环.看了半天,才意识到 Bug 在哪里. 完美解答: 数组下标越界.数组a总共有10个值,a[0]~a[9].for循环里面 ...
- python中传统除法、真除法和Floor除法
1.python2.6及其之前,x/y是传统除法,对于整数会省去小数部分,对于浮点数会保持小数部分. 2.python3中x/y表示真除法,无论任何数据类型都会保留小数部分. 3.python2和3中 ...
- Python——方法
方法是类或者对象行为特征的抽象,方法其实也是函数,它的定义方式.调用方式与函数都很相似. 一.类调用实例方法 先来看一段代码: # 定义全局空间test函数 def test(): print ('全 ...
- WUSTOJ 1235: 计算矩阵的鞍点(Java)
1235: 计算矩阵的鞍点 题目 输出二维数组中行上为最大,列上为最小的元素(称为鞍点)及其位置(行列下标).如果不存在任何鞍点,请输出"404 not found"(不带引号 ...