概述
class文件基础
作为字节码于ASM专栏文章的开篇,一直在思考已何种风格去讲诉字节码和ASM,若想理解Java语言背后的技术字节码是无论无何都无法绕开的,而如果只是仅仅对字节码进行研究也是相当的枯燥,作为程序员的我们对这些我们不能动手写点啥子的相当难受,所以我想通过对字节码+操作字节码库的联动达到学以致用的目的
作为java的操刀手我们应该都知道在我们编写代码后java通过编译后的产物是class文件,而class文件也可以用类似于Class的结构描述文件。
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
虚拟机规范规定u1、u2、u4为1、2、4字节无符号整数,cp_info、field_info、method_info 、attribute_info 与之对应相同数据类型的可变长度集合(table),并且每个table都有着对应的长度字段constant_pool_count、interfaces_count、fields_count、methods_count、attributes_count。
magic
魔数,4字节,class文件头4字节,用于虚拟机验证class文件的合法性,如果我们修改class文件头4字节运行程序会抛出异常。Java使用0XCAFEBABE作为文件的标识。
minor_version
副版本号,2字节,该值为0
major_version
主版本号,2字节,java版本与之有着一一对应的值,比如java8→52。每当Java发布大版本时就增加1。虚拟机加载类文件会检查当前环境是否低于major_version,如果低于就会抛出异常
constant_pool_count & constant_pool[]
常量池数量,2字节,常量池,索引0为保留索引,Long和Double的常量需要暂用2个索引位,所以最多n - 1个
虚拟机目前共定义14中常量类型:
类型 | 值 |
---|---|
CONSTANT_Utf8_info | 1 |
CONSTANT_Integer_info | 3 |
CONSTANT_Float_info | 4 |
CONSTANT_Long_info | 5 |
CONSTANT_Double_info | 6 |
CONSTANT_Class_info | 7 |
CONSTANT_String_info | 8 |
CONSTANT_Fieldref_info | 9 |
CONSTANT_Methodref_info | 10 |
CONSTANT_InterfaceMethodref_info | 11 |
CONSTANT_NameAndType_info | 12 |
CONSTANT_MethodHandle_info | 15 |
CONSTANT_MethodType_info | 16 |
CONSTANT_InvokeDynamic_info | 18 |
CONSTANT_Utf8_info
CONSTANT_Utf8_info存储经过MUTF-8后的字符串,tag标记类型,值1,1字节。length标记字符串长度,2字节。bytes真正存储字符串数据。由于length大小的限制,程序中生命的字面量字符串也存在这大小的限制。根据虚拟机规范我们可以得出理论上的字面量字符串长度最大位65535,但是经过实际测试字面量字符串的最大长度位65534,javac的作者如果不是出于特殊理由设置的机制那么这其实就可以算作javac的一个BUG了
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
CONSTANT_Integer_info
tag值3,bytes存储整形的值,4字节
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
CONSTANT_Float_info
tag值4,bytes存储浮点数的值,4字节
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
CONSTANT_Long_info
tag值5,high_bytes存储Long高32位数据,low_bytes存储Long低32位数据
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double_info
tag值6,high_bytes存储Double高32位数据,low_bytes存储Double低32位数据
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Class_info
tag值7,name_index指向常量池中类型CONSTANT_Utf8_info的索引,存储类全限定名
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
CONSTANT_String_info
tag值8,string_index指向常量池中类型CONSTANT_Utf8_info索引,存储字符串真正的内容
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
CONSTANT_Fieldref_info
tag值9,class_index指向常量池中类型CONSTANT_Class_info索引,表示字段所属类,name_and_type_index指向常量池中类型CONSTANT_NameAndType_info索引,表示字段名字和类型
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_Methodref_info & CONSTANT_InterfaceMethodref_info
CONSTANT_Methodref_info tag值10,CONSTANT_InterfaceMethodref_info tag值11,二者区别在于是否接口方法,class_index指向常量池中类型CONSTANT_Class_info索引,表示方法所属类,name_and_type_index指向常量池中类型CONSTANT_NameAndType_info索引,表示方法名字和签名
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_NameAndType_info
tag值12,name_index指向常量池中类型CONSTANT_Utf8_info索引,表示方法名、字段名,descriptor_index指向常量池中类型CONSTANT_Utf8_info索引,表示字段类型、方法签名
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
CONSTANT_MethodHandle_info
tag值15,该结构表示方法句柄,reference_kind值1~9,该值表示方法句柄的种类
CONSTANT_MethodHandle_info {
u1 tag;
u1 reference_kind;
u2 reference_index;
}
CONSTANT_MethodType_info
tag值16,表示一个方法类型
CONSTANT_MethodType_info {
u1 tag;
u2 descriptor_index;
}
CONSTANT_InvokeDynamic_info
tag值18,用于实现lambda关键指令,bootstrap_method_attr_index指向bootstrap_method表索引,name_and_type_index表示由javac后通过ASM所生成对应的函数
CONSTANT_InvokeDynamic_info {
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}
access_flags
访问标记位,2字节,标记类的修饰符,这些标记符可以相互组合出现,但是存在一定的互斥性,如果但从值考虑则有一条非常简单的规则就是同一位为非0值为互斥。这里多提一句的是在阅读源码不难发现相当多的库利用16进制来控制状态,得益于这样的设计,对状态的组合和校验都可以通过非常简单的算法实现,在个人项目中也可以尝试使用16进制实现某些适用的场景,体验16进制及位运算带来的简洁高效算法。
访问标记 | JVM规范 | 含义 |
---|---|---|
ACC_PUBLIC | 0x0001 | 标记类公开权限是否public |
ACC_FINAL | 0x0010 | 标记类是否final类 |
ACC_SUPER | 0x0020 | 已废除 |
ACC_INTERFACE | 0x0200 | 标记是否接口 |
ACC_ABSTRACT | 0x0400 | 标记是否抽象类 |
ACC_SYNTHETIC | 0x1000 | 标记是否为生成的类 |
ACC_ANNOTATION | 0x2000 | 标记是否注解类 |
ACC_ENUM | 0x4000 | 标记是否枚举类 |
this_class
指向常量池中类型CONSTANT_Class_info索引,表示类全限定名,2字节
super_class
指向常量池中类型CONSTANT_Class_info索引,表示父类全限定名,2字节
interfaces_count & interfaces[]
接口表数量2字节,表中类型为CONSTANT_Class_info
{
u2 interfaces_count;
interface_info interfaces[interfaces_count];
}
fields_count & fields[]
字段表数量,2字节,表中类型为field_info,提供类或接口中字段的完整描述,表中仅包含类或接口声明的字段,不包含继承的父类或者实现的接口所包含的字段。
{
u2 fields_count;
field_info fields[fields_count];
}
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
field_info:
- access_flags
标记 | 值 | 含义 |
---|---|---|
ACC_PUBLIC | 0x0001 | 标记字段是否publick |
ACC_PRIVATE | 0x0002 | 标记字段是否private |
ACC_PROTECTED | 0x0004 | 标记字段是否protected |
ACC_STATIC | 0x0008 | 标记字段是否static |
ACC_FINAL | 0x0010 | 标记字段是否final |
ACC_VOLATILE | 0x0040 | 标记字段是否volatile |
ACC_TRANSIENT | 0x0080 | 标记字段是否transient,这个不经常使用, 标记后字段不能序列化 |
ACC_SYNTHETIC | 0x1000 | 标记字段是否synthetic,这个由javac编译生成字段 |
ACC_ENUM | 0x4000 | 标记字段是否为枚举 |
-
name_index
指向常量池中CONSTANT_Utf8_info索引,表示字段名称
-
descriptor_index
指向常量池中CONSTANT_Utf8_info索引,表示字段描述
-
attributes_count & attributes[]
属性表,jvm规范约定字段属性结构为:Code_attribute、Exceptions_attribute、Synthetic_attribute、Signature_attribute、Deprecated_attribute、RuntimeVisibleAnnotations_attribute、RuntimeInvisibleAnnotations_attribute、RuntimeVisibleParameterAnnotations_attribute、RuntimeInvisibleParameterAnnotations_attribute、AnnotationDefault_attribute
methods_count & methods[]
方法表数量,2字节,表中类型为method_info,提供类或接口方法的完整描述,如果access_flags没有设置ACC_NATIVE|ACC_ABSTRACT则提供实现方法所对应的指令集,表中仅包含类或接口声明的方法,不包含继承的父类或者实现的接口所包含的方法。
{
u2 methods_count;
method_info methods[methods_count];
}
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
method_info:
- access_flags
标记 | 值 | 含义 |
---|---|---|
ACC_PUBLIC | 0x0001 | 标记方法是否publick |
ACC_PRIVATE | 0x0002 | 标记方法是否private |
ACC_PROTECTED | 0x0004 | 标记方法是否protected |
ACC_STATIC | 0x0008 | 标记方法是否static |
ACC_FINAL | 0x0010 | 标记方法是否final |
ACC_SYNCHRONIZED | 0x0020 | 标记方法是否synchronized |
ACC_BRIDGE | 0x0040 | javac生成的桥接方法 |
ACC_VARARGS | 0x0080 | 标记方法是否含有可变参数 |
ACC_NATIVE | 0x0100 | 标记方法是否native |
ACC_ABSTRACT | 0x0400 | 标记方法是否abstract |
ACC_STRICT | 0x0800 | 标记后方法浮点模式为FP-strict |
ACC_SYNTHETIC | 0x1000 | javac生成方法标记 |
-
name_index
指向常量池中CONSTANT_Utf8_info索引,表示特殊方法名称, |
-
descriptor_index
指向常量池中CONSTANT_Utf8_info索引,表示方法签名,
-
attributes_count & attributes[]
属性表,jvm规范约定方法属性结构为:Code_attribute、Exceptions_attribute、Synthetic_attribute、Signature_attribute、Deprecated_attribute、RuntimeVisibleAnnotations_attribute、RuntimeInvisibleAnnotations_attribute、RuntimeVisibleParameterAnnotations_attribute
attributes_count & attributes[]
属性表数量,2字节,属性是除了常量池之外最为复杂的结构,这里拿比较关心的几个进行介绍,其它可通过文档自行查阅
属性结构
Attribute |
---|
ConstantValue |
Code |
StackMapTable |
Exceptions |
InnerClasses |
EnclosingMethod |
Synthetic |
Signature |
SourceFile |
SourceDebugExtension |
LineNumberTable |
LocalVariableTable |
LocalVariableTypeTable |
Deprecated |
RuntimeVisibleAnnotations |
RuntimeInvisibleAnnotations |
RuntimeVisibleParameterAnnotations |
RuntimeInvisibleParameterAnnotations |
AnnotationDefault |
BootstrapMethods |
ConstantValue_attribute
常量字段值
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
ConstantValue_attribute:
-
constantvalue_index
指向常量池中CONSTANT_Long|CONSTANT_Float|CONSTANT_Double|CONSTANT_Integer|CONSTANT_String索引,存储字段初始化的值
Code_attribute
表示一个方法的指令集和一些额外的辅助信息
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Code_attribute:
-
max_stack
操作数栈最大深度,编译时确认,由指令的入栈和出栈计算出最大操作数栈长度最大值
-
max_locals
本地变量表最大值,编译时确认,但并不是简单的直接计算整个帧栈中使用到的变量总和,而是通过对每个变量的生命周期的消亡而留给后面变量复用位减少了最终大小。
-
code_length & code[]
存储方法指令集
-
exception_table_length & exception_table[]
存储方法中相关的异常表
-
start_pc
记录try索引,捕获异常开始
-
end_pc
记录正常结束索引,若执行到这里表示代码try块已正常执行
-
handler_pc
记录异常开始索引,若执行到这里表示代码try块内抛出catch_type类型异常代码走向catch代码块
-
catch_type
记录异常类型,指向常量池中类型CONSTANT_Class_info索引
-
StackMapTable_attribute
由多个或零个帧栈组成,每个帧栈指定偏移量,该结构为了加快JVM运行速度而设计。由于设计过于复杂,在我们通过ASM编写代码时建议交权给ASM帮助我们处理
StackMapTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_entries;
stack_map_frame entries[number_of_entries];
}
Exceptions_attribute
记录方法可能抛出哪些已处理异常
Exceptions_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_exceptions;
u2 exception_index_table[number_of_exceptions];
}
-
number_of_exceptions & exception_index_table[]
异常表元素类型为常量池中类型为CONSTANT_Class_info,该类型必须为RuntimeException | Error子类**
InnerClasses_attribute
记录内部类和外部类关系
InnerClasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
{ u2 inner_class_info_index;
u2 outer_class_info_index;
u2 inner_name_index;
u2 inner_class_access_flags;
} classes[number_of_classes];
}
-
number_of_classes & classes[]
-
inner_class_info_index
指向常量池类型为CONSTANT_Class_info索引,表示内部类
-
outer_class_info_index
指向常量池类型为CONSTANT_Class_info索引,表示外部类
-
inner_name_index
指向常量池类型为CONSTANT_Utf8_info索引,表示内部类全限定名
-
inner_class_access_flags
内部类访问标记
-
LineNumberTable_attribute
标记字节码和源码对应行号
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{ u2 start_pc;
u2 line_number;
} line_number_table[line_number_table_length];
}
-
line_number_table_length & line_number_table[]
-
start_pc
字节码指令
-
line_number
源码行号
-
LocalVariableTable_attribute
记录方法本地变量表
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];
}
-
local_variable_table_length & local_variable_table[]
-
start_pc & length
记录变量在字节码中存在的范围[start_pc, start_pc + length),也就是说这个时变量生命消亡记录的关键数据
-
name_index
指向常量池中类型CONSTANT_Utf8_info索引,表示变量名称
-
descriptor_index
指向常量池中类型CONSTANT_Utf8_info索引,表示变量类型签名
-
index
表示变量位于帧栈本地变量表中位置,需要注意的时Long和Double占用两个位置
-
LocalVariableTypeTable_attribute
于LocalVariableTable_attribute记录信息类似,不同是它记录的不是描述而是签名
Deprecated_attribute
表示类、字段、方法已废除
RuntimeVisibleAnnotations_attribute
记录运行时注解信息
RuntimeVisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
annotation {
u2 type_index;
u2 num_element_value_pairs;
{ u2 element_name_index;
element_value value;
} element_value_pairs[num_element_value_pairs];
}
element_value {
u1 tag;
union {
u2 const_value_index;
{ u2 type_name_index;
u2 const_name_index;
} enum_const_value;
u2 class_info_index;
annotation annotation_value;
{ u2 num_values;
element_value values[num_values];
} array_value;
} value;
}
annotation:
-
type_index
指向常量池中类型CONSTANT_Utf8_info索引,表示注解描述类型
-
num_element_value_pairs & element_value_pairs[]
-
element_name_index
指向常量池中类型CONSTANT_Utf8_info索引,表示注解字段描述
-
value
类型element_value,描述注解字段对应值
-
RuntimeInvisibleAnnotations_attribute
于RuntimeVisibleAnnotations_attribute类似,但无法通过反射获取注解信息
RuntimeVisibleParameterAnnotations_attribute
于RuntimeVisibleAnnotations_attribute类似,但作用于方法参数
RuntimeInvisibleParameterAnnotations_attribute
于RuntimeInvisibleAnnotations_attribute类似,但作用于方法参数
AnnotationDefault_attribute
记录结构所表示元素的默认值
BootstrapMethods_attribute
虚拟机对动态语言lambda支持实现的重要结构,对_invokedynamic指令的描述。_
BootstrapMethods_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_bootstrap_methods;
{ u2 bootstrap_method_ref;
u2 num_bootstrap_arguments;
u2 bootstrap_arguments[num_bootstrap_arguments];
} bootstrap_methods[num_bootstrap_methods];
}
-
num_bootstrap_methods & bootstrap_methods
-
bootstrap_method_ref
指向常量池中类型为CONSTANT_MethodHandle_info索引,表示方法句柄
-
num_bootstrap_arguments & bootstrap_arguments[]
元素指向常量池中CONSTANT_String_info、CONSTANT_Class_info、CONSTANT_Integer_info、CONSTANT_Long_info、CONSTANT_Float_info、CONSTANT_Double_info、CONSTANT_MethodHandle_info、CONSTANT_MethodType_info
-
掌握上诉构成class文件的结构也是字节码相关内容的起步,不积硅步无以至千里。
图片是学习编程起步的hello world对应的class文件,文件使用16进制打开查看,这里提及下16进制的每个字符等于0.5字节,16进制中1个字符可以表示0~15,转换二进制242^424,1字节等于8比特,所以推导出16进制的内存占用。
字节 | 结构或字段 | 含义 |
CA FE BA BE | magic | 文件魔数 |
00 00 | minor_version | 副版本号 |
00 34 | major_version | 主版本号,52,JAVA8 |
00 22 | constant_pool_count | 常量池大小,33 = 34(0X22) - 1 |
0A 00 06 00 14 | cp_info | #1 0A tag,CONSTANT_Methodref 00 06 class_index,java/lang/Object 00 14 name_and_type_index,<init> ()V |
09 00 15 00 16 | cp_info | #2 09 tag,CONSTANT_Fieldref 00 15 class_index,java/lang/System 00 16 name_and_type_index,out Ljava/io/PrintStream; |
08 00 17 | cp_info | #3 08 tag,CONSTANT_String 00 17 string_index,hello world |
0A 00 18 00 19 | cp_info | #4 0A CONSTANT_Methodref 00 18 class_index,java/io/PrintStream 00 19 name_and_type_index,println (Ljava/lang/String;)V |
07 00 1A | cp_info | #5 07 CONSTANT_Class 00 1A name_index,HelloWorld |
07 00 1B | cp_info | #6 07 CONSTANT_Class 00 1B name_index,java/lang/Object |
01 00 06 3C 69 6E 69 74 3E | cp_info | #7 01 CONSTANT_Utf8 00 06 length 3C 69 6E 69 74 3E <init> |
01 00 03 28 29 56 | cp_info | #8 01 CONSTANT_Utf8 00 03 length 28 29 56 ()V |
01 00 04 43 6F 64 65 | cp_info | #9 01 CONSTANT_Utf8 00 04 length 43 6F 64 65 Code |
01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 | cp_info | #10 01 CONSTANT_Utf8 00 0F length 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 LineNumberTable |
01 00 12 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65 | cp_info | #11 01 CONSTANT_Utf8 00 12 length 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65 LocalVariableTable |
01 00 04 74 68 69 73 | cp_info | #12 01 CONSTANT_Utf8 00 04 length 74 68 69 73 this |
01 00 0C 4C 48 65 6C 6C 6F 57 6F 72 6C 64 3B | cp_info | #13 01 CONSTANT_Utf8 00 0C length 4C 48 65 6C 6C 6F 57 6F 72 6C 64 3B LHelloWorld; |
01 00 04 6D 61 69 6E | cp_info | #14 01 CONSTANT_Utf8 00 04 length 6D 61 69 6E main |
01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 | cp_info | #15 01 CONSTANT_Utf8 00 16 length 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 ([Ljava/lang/String;)V |
01 00 04 61 72 67 73 | cp_info | #16 01 CONSTANT_Utf8 00 04 length 61 72 67 73 args |
01 00 13 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B | cp_info | #17 01 CONSTANT_Utf8 00 13 length 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B [Ljava/lang/String; |
01 00 0A 53 6F 75 72 63 65 46 69 6C 65 | cp_info | #18 01 CONSTANT_Utf8 00 0A length 53 6F 75 72 63 65 46 69 6C 65 SourceFile |
01 00 0F 48 65 6C 6C 6F 57 6F 72 6C 64 2E 6A 61 76 61 | cp_info | #19 01 CONSTANT_Utf8 00 0F length 48 65 6C 6C 6F 57 6F 72 6C 64 2E 6A 61 76 61 HelloWorld.java |
0C 00 07 00 08 | cp_info | #20 0C CONSTANT_NameAndType 00 07 name_index,<init> 00 08 descriptor_index,()V |
07 00 1C | cp_info | #21 07 CONSTANT_Class 00 1C name_index,java/lang/System |
0C 00 1D 00 1E | cp_info | #22 0C CONSTANT_NameAndType 00 1D name_index,out 00 1E descriptor_index,Ljava/io/PrintStream; |
01 00 0B 68 65 6C 6C 6F 20 77 6F 72 6C 64 | cp_info | #23 01 CONSTANT_Utf8 00 0B length 68 65 6C 6C 6F 20 77 6F 72 6C 64 hello world |
07 00 1F | cp_info | #24 07 CONSTANT_Class 00 1F name_index,java/io/PrintStream |
0C 00 20 00 21 | cp_info | #25 0C CONSTANT_NameAndType 00 20 name_index,println 00 21 descriptor_index,(Ljava/lang/String;)V |
01 00 0A 48 65 6C 6C 6F 57 6F 72 6C 64 | cp_info | #26 01 CONSTANT_Utf8 00 0A length 48 65 6C 6C 6F 57 6F 72 6C 64 HelloWorld |
01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 | cp_info | #27 01 CONSTANT_Utf8 00 10 length 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 java/lang/Object |
01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D | cp_info | #28 01 CONSTANT_Utf8 00 10 length 6A 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D java/lang/System |
01 00 03 6F 75 74 | cp_info | #29 03 CONSTANT_Utf8 00 03 length 6F 75 74 out |
01 00 15 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B | cp_info | #30 03 CONSTANT_Utf8 00 15 length 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B Ljava/io/PrintStream; |
01 00 13 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D | cp_info | #31 03 CONSTANT_Utf8 00 13 length 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D java/io/PrintStream |
01 00 07 70 72 69 6E 74 6C 6E | cp_info | #32 03 CONSTANT_Utf8 00 07 length 70 72 69 6E 74 6C 6E println |
01 00 15 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 | cp_info | #33 03 CONSTANT_Utf8 00 15 length 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 (Ljava/lang/String;)V |
00 21 | access_flags | ACC_PUBLIC + ACC_SUPER |
00 05 | this_class | HelloWorld |
00 06 | super_class | java/lang/Object |
00 00 | interfaces_count | 类实现0个接口 |
00 00 | fields_count | 类包含0个字段 |
00 02 | methods_count | 类包含2个方法 |
- | - | 构造方法字节码开始 |
00 01 00 07 00 08 00 01 00 09 00 00 00 2F 00 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 02 00 0A 00 00 00 06 00 01 00 00 00 06 00 0B 00 00 00 0C 00 01 00 00 00 05 00 0C 00 0D 00 00 | method_info | 00 01 access_flags,ACC_PUBLIC 00 07 name_index,<init> 00 08 descriptor_index,()V 00 01 attributes_count 00 09 attribute_name_index,Code 00 00 00 2F attribute_length 00 01 max_stack 00 01 max_locals 00 00 00 05 code_length 2A ALOAD_0 B7 INVOKESPECIAL 00 01 java/lang/Object ()V B1 RETURN 00 00 exception_table_length 00 02 attributes_count 00 0A LineNumberTable 00 00 00 06 attribute_length 00 01 line_number_table_length 00 00 start_pc 00 06 line_number 00 0B LocalVariableTable 00 00 00 0C attribute_length 00 01 local_variable_table_length 00 00 start_pc 00 05 length 00 0C name_index,this 00 0D descriptor_index,LHelloWorld; 00 00 index |
- | - | 构造方法字节码结束 |
- | - | main方法开始 |
00 09 00 0E 00 0F 00 01 00 09 00 00 00 37 00 02 00 01 00 00 00 09 B2 00 02 12 03 B6 00 04 B1 00 00 00 02 00 0A 00 00 00 0A 00 02 00 00 00 08 00 08 00 09 00 0B 00 00 00 0C 00 01 00 00 00 09 00 10 00 11 00 00 | method_info | 00 09 access_flags,ACC_PUBLIC + ACC_STATIC 00 0E name_index,main 00 0F descriptor_index,([Ljava/lang/String;)V 00 01 attributes_count 00 09 attribute_name_index,Code 00 00 00 37 attribute_length 00 02 max_stack 00 01 max_locals 00 00 00 09 code_length B2 GETSTATIC 00 02 java/lang/System out Ljava/io/PrintStream; 12 LDC 03 hello world B6 INVOKEVIRTUAL 00 04 java/io/PrintStream println (Ljava/lang/String;)V B1 RETURN 00 00 exception_table_length 00 02 attributes_count 00 0A LineNumberTable 00 00 00 0A attribute_length 00 02 line_number_table_length 00 00 start_pc 00 08 line_number 00 08 start_pc 00 09 line_number 00 0B LocalVariableTable 00 00 00 0C attribute_length 00 01 local_variable_table_length 00 00 start_pc 00 09 length 00 10 name_index,args 00 11 descriptor_index,[Ljava/lang/String; 00 00 index |
- | - | main方法结束 |
00 01 | attributes_count | 类属性个数1 |
00 12 00 00 00 02 00 13 | attribute_info | #1 00 12 attribute_name_index,SourceFile 00 00 00 02 attribute_length 00 13 sourcefile_index,HelloWorld.java |
以HelloWorld编译后的源码文件分析完毕,简简单单一句话但是对于编译后的产物并非那么简单,作为深入理解ClassFile
的简单代码还是相对容易看得懂的,复杂的代码要是以这种形式阅读几乎和阅读机器语言的难度一致了,所以通常使用javac、javap命令帮助我们查看编译后产物信息。
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
全套视频资料:
一、面试合集
二、源码解析合集
三、开源框架合集
欢迎大家一键三连支持,若需要文中资料,直接扫码免费领取↓↓↓
最后
以上就是会撒娇溪流为你收集整理的【Android】字节码&ASM-class文件刨析class文件基础的全部内容,希望文章能够帮你解决【Android】字节码&ASM-class文件刨析class文件基础所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复