zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

【Android】字节码&ASM-class文件刨析

2023-09-27 14:22:52 时间

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_info1
CONSTANT_Integer_info3
CONSTANT_Float_info4
CONSTANT_Long_info5
CONSTANT_Double_info6
CONSTANT_Class_info7
CONSTANT_String_info8
CONSTANT_Fieldref_info9
CONSTANT_Methodref_info10
CONSTANT_InterfaceMethodref_info11
CONSTANT_NameAndType_info12
CONSTANT_MethodHandle_info15
CONSTANT_MethodType_info16
CONSTANT_InvokeDynamic_info18

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_PUBLIC0x0001标记类公开权限是否public
ACC_FINAL0x0010标记类是否final类
ACC_SUPER0x0020已废除
ACC_INTERFACE0x0200标记是否接口
ACC_ABSTRACT0x0400标记是否抽象类
ACC_SYNTHETIC0x1000标记是否为生成的类
ACC_ANNOTATION0x2000标记是否注解类
ACC_ENUM0x4000标记是否枚举类

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_PUBLIC0x0001标记字段是否publick
ACC_PRIVATE0x0002标记字段是否private
ACC_PROTECTED0x0004标记字段是否protected
ACC_STATIC0x0008标记字段是否static
ACC_FINAL0x0010标记字段是否final
ACC_VOLATILE0x0040标记字段是否volatile
ACC_TRANSIENT0x0080标记字段是否transient,这个不经常使用, 标记后字段不能序列化
ACC_SYNTHETIC0x1000标记字段是否synthetic,这个由javac编译生成字段
ACC_ENUM0x4000标记字段是否为枚举
  • 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_PUBLIC0x0001标记方法是否publick
ACC_PRIVATE0x0002标记方法是否private
ACC_PROTECTED0x0004标记方法是否protected
ACC_STATIC0x0008标记方法是否static
ACC_FINAL0x0010标记方法是否final
ACC_SYNCHRONIZED0x0020标记方法是否synchronized
ACC_BRIDGE0x0040javac生成的桥接方法
ACC_VARARGS0x0080标记方法是否含有可变参数
ACC_NATIVE0x0100标记方法是否native
ACC_ABSTRACT0x0400标记方法是否abstract
ACC_STRICT0x0800标记后方法浮点模式为FP-strict
ACC_SYNTHETIC0x1000javac生成方法标记
  • 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文件的结构也是字节码相关内容的起步,不积硅步无以至千里。

49580512-3C00-456d-8BD2-30E4F1A58076.png

图片是学习编程起步的hello world对应的class文件,文件使用16进制打开查看,这里提及下16进制的每个字符等于0.5字节,16进制中1个字符可以表示0~15,转换二进制242^424,1字节等于8比特,所以推导出16进制的内存占用。

字节结构或字段含义
CA FE BA BEmagic文件魔数
00 00minor_version副版本号
00 34major_version主版本号,52,JAVA8
00 22constant_pool_count常量池大小,33 = 34(0X22) - 1
0A 00 06 00 14cp_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 16cp_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 17cp_info#3
08
tag,CONSTANT_String
00 17
string_index,hello world
0A 00 18 00 19cp_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 1Acp_info#5
07
CONSTANT_Class
00 1A
name_index,HelloWorld
07 00 1Bcp_info#6
07
CONSTANT_Class
00 1B
name_index,java/lang/Object
01 00 06 3C 69 6E 69 74 3Ecp_info#7
01
CONSTANT_Utf8
00 06
length
3C 69 6E 69 74 3E
<init>
01 00 03 28 29 56cp_info#8
01
CONSTANT_Utf8
00 03
length
28 29 56
()V
01 00 04 43 6F 64 65cp_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 65cp_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 65cp_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 73cp_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 3Bcp_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 6Ecp_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 56cp_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 73cp_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 3Bcp_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 65cp_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 61cp_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 08cp_info#20
0C
CONSTANT_NameAndType
00 07
name_index,<init> 00 08
descriptor_index,()V
07 00 1Ccp_info#21
07
CONSTANT_Class
00 1C
name_index,java/lang/System
0C 00 1D 00 1Ecp_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 64cp_info#23
01
CONSTANT_Utf8
00 0B
length
68 65 6C 6C 6F 20 77 6F 72 6C 64
hello world
07 00 1Fcp_info#24
07
CONSTANT_Class
00 1F
name_index,java/io/PrintStream
0C 00 20 00 21cp_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 64cp_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 74cp_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 6Dcp_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 74cp_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 3Bcp_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 6Dcp_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 6Ecp_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 56cp_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 21access_flagsACC_PUBLIC + ACC_SUPER
00 05this_classHelloWorld
00 06super_classjava/lang/Object
00 00interfaces_count类实现0个接口
00 00fields_count类包含0个字段
00 02methods_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 00method_info00 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 00method_info00 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 01attributes_count类属性个数1
00 12 00 00 00 02 00 13attribute_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开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集
在这里插入图片描述
二、源码解析合集

在这里插入图片描述
三、开源框架合集

在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接扫码免费领取↓↓↓