—> go to 总目录
从一个class文件看字节码结构。 java虚机规范
一、Demo
1.1 Demo.java
仅有一个变量,一个方法。
package com. httpserver;
public class Demo {
private int num = 1 ;
public int add ( ) {
num = num + 2 ;
return num;
}
}
1.2 反编译的真实java文件
可以看出来多了this
1.3 Demo.class
00000000: cafe babe 0000 0034 0016 0a00 0400 1209 .......4........
00000010: 0003 0013 0700 1407 0015 0100 036e 756d .............num
00000020: 0100 0149 0100 063c 696e 6974 3e01 0003 ...I...<init>...
00000030: 2829 5601 0004 436f 6465 0100 0f4c 696e ()V...Code...Lin
00000040: 654e 756d 6265 7254 6162 6c65 0100 124c eNumberTable...L
00000050: 6f63 616c 5661 7269 6162 6c65 5461 626c ocalVariableTabl
00000060: 6501 0004 7468 6973 0100 154c 636f 6d2f e...this...Lcom/
00000070: 6874 7470 7365 7276 6572 2f44 656d 6f3b httpserver/Demo;
00000080: 0100 0361 6464 0100 0328 2949 0100 0a53 ...add...()I...S
00000090: 6f75 7263 6546 696c 6501 0009 4465 6d6f ourceFile...Demo
000000a0: 2e6a 6176 610c 0007 0008 0c00 0500 0601 .java...........
000000b0: 0013 636f 6d2f 6874 7470 7365 7276 6572 ..com/httpserver
000000c0: 2f44 656d 6f01 0010 6a61 7661 2f6c 616e /Demo...java/lan
000000d0: 672f 4f62 6a65 6374 0021 0003 0004 0000 g/Object.!......
000000e0: 0001 0002 0005 0006 0000 0002 0001 0007 ................
000000f0: 0008 0001 0009 0000 0038 0002 0001 0000 .........8......
00000100: 000a 2ab7 0001 2a04 b500 02b1 0000 0002 ..*...*.........
00000110: 000a 0000 000a 0002 0000 0009 0004 000a ................
00000120: 000b 0000 000c 0001 0000 000a 000c 000d ................
00000130: 0000 0001 000e 000f 0001 0009 0000 003d ...............=
00000140: 0003 0001 0000 000f 2a2a b400 0205 60b5 ........**....`.
00000150: 0002 2ab4 0002 ac00 0000 0200 0a00 0000 ..*.............
00000160: 0a00 0200 0000 0d00 0a00 0e00 0b00 0000 ................
00000170: 0c00 0100 0000 0f00 0c00 0d00 0000 0100 ................
00000180: 1000 0000 0200 110a ........
1.4 javap -verbose
jdk自带反解析工具
Classfile /Users/sunqiyuan/Desktop/Demo.class
Last modified 2020年4月28日; size 391 bytes
SHA-256 checksum 91497ea9c8db954d68c9206e1c17a2251658351718284cf92d73fac35c10e8d5
Compiled from "Demo.java"
public class com.httpserver.Demo
minor version: 0
major version: 52
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #3 // com/httpserver/Demo
super_class: #4 // java/lang/Object
interfaces: 0, fields: 1, methods: 2, attributes: 1
Constant pool:
#1 = Methodref #4.#18 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#19 // com/httpserver/Demo.num:I
#3 = Class #20 // com/httpserver/Demo
#4 = Class #21 // java/lang/Object
#5 = Utf8 num
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/httpserver/Demo;
#14 = Utf8 add
#15 = Utf8 ()I
#16 = Utf8 SourceFile
#17 = Utf8 Demo.java
#18 = NameAndType #7:#8 // "<init>":()V
#19 = NameAndType #5:#6 // num:I
#20 = Utf8 com/httpserver/Demo
#21 = Utf8 java/lang/Object
{
public com.httpserver.Demo();
descriptor: ()V
flags: (0x0001) 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 num:I
9: return
LineNumberTable:
line 9: 0
line 10: 4
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lcom/httpserver/Demo;
public int add();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
Code:
stack=3, locals=1, args_size=1
0: aload_0
1: aload_0
2: getfield #2 // Field num:I
5: iconst_2
6: iadd
7: putfield #2 // Field num:I
10: aload_0
11: getfield #2 // Field num:I
14: ireturn
LineNumberTable:
line 13: 0
line 14: 10
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this Lcom/httpserver/Demo;
}
SourceFile: "Demo.java"
1.5 字节码解析
javap是以人类可读的方式解析字节码。 这张图把字节码进行了标注和javap的字段是一一对应的 中文版 方便快速理解
英文版 方便准确理解
1.6 字节码结构(速查)
字节码本质是一张表。一张有结构从上到下的表。它的字段编码是有规范的,直观的就是javap 反解析出来的格式,和字节码一一对应。下面就是字节码的结构。
类型 名称 说明 长度 u4 magic 魔数,识别Class文件格式 4个字节 u2 minor_version 副版本号 2个字节 u2 major_version 主版本号 2个字节 u2 constant_pool_count 常量池计算器 2个字节 cp_info constant_pool 常量池 n个字节 u2 access_flags 访问标志 2个字节 u2 this_class 类索引 2个字节 u2 super_class 父类索引 2个字节 u2 interfaces_count 接口计数器 2个字节 u2 interfaces 接口索引集合 2个字节 u2 fields_count 字段个数 2个字节 field_info fields 字段集合 n个字节 u2 methods_count 方法计数器 2个字节 method_info methods 方法集合 n个字节 u2 attributes_count 附加属性计数器 2个字节 attribute_info attributes 附加属性集合 n个字节
字段说明
数据类型 定义 说明 u* 无符号整数 例如u1就是一个字节 info 表,复合数据 通常没有固定长度,以_info
结尾,通常前面都会长度
length说明
1.7 常用表(速查)
1.7.1 常量类型表
基本概念
常量池主要存放两大常量:字面量literals (string, integer, and floating point constants)
和符号引用 Symbolic References
常量 具体的常量 解释 字面量 文本字符串 声明为final的常量值 符号引用 类和接口的全限定名 形如com/sun/Demo;com/sun/Hello
,把 .
换成 /
,多个用 ;
隔离 字段的名称和描述符 简单名称:
比如add()和num()的简单名称是add
和num
方法的名称和描述符 描述符:
描述符表
描述符的作用是用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值。根据描述符规则,基本数据类型(byte、char、double、float、int、long、short、boolean)以及代表无返回值的void类型都用一个大写字符来表示,而对象类型则用字符L加对象的全限定名来表示,详见下表:
标志符 含义 B 基本数据类型byte C 基本数据类型char D 基本数据类型double F 基本数据类型float I 基本数据类型int J 基本数据类型long S 基本数据类型short Z 基本数据类型boolean V 基本数据类型void L 对象类型,如Ljava/lang/Object
正式表(14个)
类型 标志 16进制 描述 CONSTANT_utf8_info 1 1 UTF-8编码的字符串 CONSTANT_Integer_info 3 3 整形字面量 CONSTANT_Float_info 4 4 浮点型字面量 CONSTANT_Long_info 5 5 长整型字面量 CONSTANT_Double_info 6 6 双精度浮点型字面量 CONSTANT_Class_info 7 7 类或接口的符号引用 CONSTANT_String_info 8 8 字符串类型字面量 CONSTANT_Fieldref_info 9 9 字段的符号引用 CONSTANT_Methodref_info 10 a 类中方法的符号引用 CONSTANT_InterfaceMethodref_info 11 b 接口中方法的符号引用 CONSTANT_NameAndType_info 12 c 字段或方法的符号引用 CONSTANT_MethodHandle_info 15 e 表示方法句柄 CONSTANT_MothodType_info 16 10 标志方法类型 CONSTANT_InvokeDynamic_info 18 12 表示一个动态方法调用点
详解
1.7.2 类访问权限控制表(修饰符)
常量池后面就是访问标志,用两个字节来表示,其标识了类或者接口的访问信息,比如:该Class文件是类还是接口,是否被定义成public
,是否是abstract
,如果是类,是否被声明成final
等等
标志名称 标志值 含义 ACC_PUBLIC 0x0001 是否为Public类型 ACC_FINAL 0x0010 是否被声明为final,只有类可以设置 ACC_SUPER 0x0020 是否允许使用invokespecial字节码指令的新语义,JDK1 ACC_INTERFACE 0x0200 标志这是一个接口 ACC_ABSTRACT 0x0400 是否为abstract类型,对于接口或者抽象类来说,次标志值为真,其他类型为假 ACC_SYNTHETIC 0x1000 标志这个类并非由用户代码产生 ACC_ANNOTATION 0x2000 标志这是一个注解 ACC_ENUM x4000 标志这是一个枚举
1.7.3(field)字段表
访问权限控制(修饰符)
public
、private
、protected
)、static修饰符
、final修饰符
、volatile
等等
标志名称 标志值 含义 ACC_PUBLIC 0x0001 字段是否为public ACC_PRIVATE 0x0002 字段是否为private ACC_PROTECTED 0x0004 字段是否为protected ACC_STATIC 0x0008 字段是否为static ACC_FINAL 0x0010 字段是否为final ACC_VOLATILE 0x0040 字段是否为volatile ACC_TRANSTENT 0x0080 字段是否为transient ACC_SYNCHETIC 0x1000 字段是否为由编译器自动产生 ACC_ENUM 0x4000 字段是否为enum
字段表结构
类型 名称 含义 数量 u2 access_flags 访问标志 1 u2 name_index 字段名索引 1 u2 descriptor_index 描述符索引 1 u2 attributes_count 属性计数器 1 attribute_info attributes 属性集合 attributes_count
1.7.4 方法
访问权限(修饰符)
标志名称 标志值 含义 ACC_PUBLIC 0x0001 方法是否为public ACC_PRIVATE 0x0002 方法是否为private ACC_PROTECTED 0x0004 方法是否为protected ACC_STATIC 0x0008 方法是否为static ACC_FINAL 0x0010 方法是否为final ACC_SYHCHRONRIZED 0x0020 方法是否为synchronized ACC_BRIDGE 0x0040 方法是否是有编译器产生的方法 ACC_VARARGS 0x0080 方法是否接受参数 ACC_NATIVE 0x0100 方法是否为native ACC_ABSTRACT 0x0400 方法是否为abstract ACC_STRICTFP 0x0800 方法是否为strictfp ACC_SYNTHETIC 0x1000 方法是否是有编译器自动产生的
方法表结构
类型 名称 含义 数量 u2 access_flags 访问标志 1 u2 name_index 方法名索引 1 u2 descriptor_index 描述符索引 1 u2 attributes_count 属性计数器 1 attribute_info attributes 属性集合 attributes_count
1.7.5 属性表
官方 一个属性表被用在ClassFile
,field_info
和method_info
和 Code_attribute
。
属性表的结构
类型 名称 数量 含义 u2 attribute_name_index 1 属性名索引 u2 attribute_length 1 属性长度 u1 info attribute_length 属性表
jvm预定义的属性表
属性名称 使用位置 含义 Code 方法表 Java代码编译成的字节码指令 ConstantValue 字段表 final关键字定义的常量池 Deprecated 类,方法,字段表 被声明为deprecated的方法和字段 Exceptions 方法表 方法抛出的异常 EnclosingMethod 类文件 仅当一个类为局部类或者匿名类是才能拥有这个属性,这个属性用于标识这个类所在的外围方法 InnerClass 类文件 内部类列表 LineNumberTable Code属性 Java源码的行号与字节码指令的对应关系 LocalVariableTable Code属性 方法的局部变量描述 StackMapTable Code属性 JDK1 Signature 类,方法表,字段表 用于支持泛型情况下的方法签名 SourceFile 类文件 记录源文件名称 SourceDebugExtension 类文件 用于存储额外的调试信息 Synthetic 类,方法表,字段表 标志方法或字段为编译器自动生成的 LocalVariableTypeTable 类 使用特征签名代替描述符,是为了引入泛型语法之后能描述泛型参数化类型而添加 RuntimeVisibleAnnotations 类,方法表,字段表 为动态注解提供支持 RuntimeInvisibleAnnotations 表,方法表,字段表 用于指明哪些注解是运行时不可见的 RuntimeVisibleParameterAnnotation 方法表 作用与RuntimeVisibleAnnotations属性类似,只不过作用对象为方法 RuntimeInvisibleParameterAnnotation 方法表 作用与RuntimeInvisibleAnnotations属性类似,作用对象哪个为方法参数 AnnotationDefault 方法表 用于记录注解类元素的默认值 BootstrapMethods 类文件 用于保存invokeddynamic指令引用的引导方式限定符
举例 code属性表
类型 名称 数量 含义 u2 attribute_name_index 1 属性名索引 u4 attribute_length 1 属性长度 u2 max_stack 1 操作数栈深度的最大值 u2 max_locals 1 局部变量表所需的存续空间 u4 code_length 1 字节码指令的长度 u1 code code_length 存储字节码指令 u2 exception_table_length 1 异常表长度 exception_info exception_table exception_length 异常表 u2 attributes_count 1 属性集合计数器 attribute_info attributes attributes_count 属性集合
LineNumberTable属性表结构
类型 名称 数量 含义 u2 attribute_name_index 1 属性名索引 u4 attribute_length 1 属性长度 u2 line_number_table_length 1 行号表长度 line_number_info line_number_table line_number_table_length 行号表
LocalVariableTable 属性
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc;
u2 length;
u2 name_index;
u2 descriptor_index;
u2 index;
} local_variable_table[local_variable_table_length];
}
LineNumberTable属性
类型 名称 数量 含义 u2 attribute_name_index 1 属性名索引 u4 attribute_length 1 属性长度 u2 line_number_table_length 1 行号表长度 line_number_info line_number_table line_number_table_length 行号表
二、讲解
引用