![](https://img.haomeiwen.com/i8207483/d379ee868e690f00.jpg)
访问标志
访问标志信息包括该 Class 文件是类还是接口,是否被定义成 public,是否是 abstract,如果是类,是否声明为 final。
![](https://img.haomeiwen.com/i8207483/5719d7c8840a03b6.jpeg)
通过名字大家都很清楚是什么意思。
- ACC_SUPER 子类调用父类一些相关方法
看一看我们字节码中是 00 21
(访问标识),表中并没有 21 对应标志。在访问标志可以两个标志的组合。其实这里 00 21 是 ACC_PUBLIC 和 ACC_SUPER 的组合。
public class Tut
类名称
00 05
这里是一个常量池中索引对应
#5 = Class #32 // com/zidea/Tut
对应当前类名称
父类名称
00 06
对应父类名字
#6 = Class #33 // java/lang/Object
接口
00 00
表示当前类实现的接口数量,这里为 0 也就是没有实现接口,接口表也不会出现。
字段
00 02
说明我们 Tut 有两个字段
private String title = "basic";
private int courses = 10;
下表表示我们字段表每一个字段的信息
![](https://img.haomeiwen.com/i8207483/523481e2cd902095.jpeg)
表示字段数量,表示字段表的,所谓字段表用于描述类和接口中声明的变量(包括类级别变量和实例变量,但不包括方法内局部变量)
- 并不是没有字段都有
attributes_count
属性,如果其值为 0,没有attribute_info
也就不存在。
private String title = "basic";
00 02 (access_flags) 表示私有的
00 07 (name_index) #7 = Utf8 title
00 08 (descriptor_index) #8 = Utf8 Ljava/lang/String;
00 00 (attributes_count) 因为是 0 所以不会出现没有attribute_info
private int courses = 10;
这个大家自己做吧。根据规则来推测这个字段的信息
00 02
0 09
00 0A
00 00
方法
{
"method_info":{
"access_flag":"方法标志",
"name_index":"方法名称",
"descriptor_index":"方法描述,方法长啥样,返回值和参数",
"attributes_count":"属性表长度",
"attribute_info":[
{
"attribute_name_index":"属性名索引",
"attribute_length":"",
"info":[
]
}
]
}
}
通过一个 json 来表示这部分字节码的结构。
00 05
表示有 5 个方法,随后继续进行分析。来看一看方法表
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getCourses() {
return courses;
}
public void setCourses(int courses) {
this.courses = courses;
}
在 Tut 类中定义了 4 个 setter
和getter
方法,再加上编译默认生成空构造方法就一共 5 个方法。
![](https://img.haomeiwen.com/i8207483/523481e2cd902095.jpeg)
00 01 (access_flags) 表示共有方法 ACC_PUBLIC
00 0B (name_index) #11 = Utf8 <init> 表示函数名字,一看到 init 就知道这个是函数构造方法。
00 0C (descriptor_index) #12 = Utf8 ()V 用于描述函数结构,也就是函数具体样子。
00 01(attributes_count) 表示有一个属性
我们需要了解一些方法属性结构attributes_count
00 0D (13 )(attribute_name_index)对应常量池 #13 = Utf8 Code
- Code 表示这个方法执行的代码
00 00 00 43 (67) (attribute_length) 表示会占据 67 字节做 code 指令,也就是函数体的内容。
00
JVM预定义了部分 attribute,编译器自己也可以实现自己的 attribute 写入 class 文件,供运行时使用。
看看 code 这部分的结构,
"code_attribute":{
"attribute_name_index":"u2",
"attribute_length":"u4",
"max_stack":"u2",
"max_locals":"u2",
"code_length":"u4",
"code[code_length]":"u1",
"exception_table_length":"u1",
"exception_table[exception_table_length]":[
{
"start_pc":"u2",
"end_pc":"u2",
"handler_pc":"u2",
"catch_type":"u2"
}
],
"attribute_count":"u2",
"attribute_info":[
]
}
这是一个很重要部分内容,所以需要花时间和精力在上面
- attribute_length :表示 attribute 所包含的字节数,不包含 attribute_name_index 和 attribute_length 字段
- max_stack : 这个方法运行的任何时刻所能达到的操作数栈的最大深度
- max_locals : 方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量
- code_length : 方法所包含的字节码的字节数以及具体的指令码
- exception_table : 存放异常处理信息
- start_pc 和 end_pc 表示在 code 数组中从 start_pc 到 end_pc 处的指令抛出的异常会由这个表项进行处理
- handler_pc 表示处理异常的代码的开始处。catch_type 表示会被处理的异常类型。
00 02 (max_stack)
00 01 (max_locals)
00 00 00 11(code) 长度 17
为了便于我们查看字节码引入一个 jclasslib 来更直观查看字节码,可以独立安装也可以安装 idea 的插件,这里我用的是插件
![](https://img.haomeiwen.com/i8207483/92a09e164558bcb1.png)
![](https://img.haomeiwen.com/i8207483/33eb47f1d9f9a6c2.png)
![](https://img.haomeiwen.com/i8207483/1fe0afbc591ea3a2.png)
附加属性
-
LineNumberTable:表示 code 数组中的字节码和 java 代码行数之间的关系。这个属性可以用于在调试的时候定位代码行数。
LineNumberTable
网友评论