上一篇 <<
java源代码
public class UserEntity {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
javac编译后字节码文件内容
CA FE BA BE 00 00 00 34 00 18 0A 00 04 00 14 09
00 03 00 15 07 00 16 07 00 17 01 00 08 75 73 65
72 4E 61 6D 65 01 00 12 4C 6A 61 76 61 2F 6C 61
6E 67 2F 53 74 72 69 6E 67 3B 01 00 06 3C 69 6E
69 74 3E 01 00 03 28 29 56 01 00 04 43 6F 64 65
01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62
6C 65 01 00 12 4C 6F 63 61 6C 56 61 72 69 61 62
6C 65 54 61 62 6C 65 01 00 04 74 68 69 73 01 00
20 4C 63 6F 6D 2F 6A 61 72 79 65 2F 6A 61 76 61
61 73 69 73 74 2F 55 73 65 72 45 6E 74 69 74 79
3B 01 00 0B 67 65 74 55 73 65 72 4E 61 6D 65 01
00 14 28 29 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53
74 72 69 6E 67 3B 01 00 0B 73 65 74 55 73 65 72
4E 61 6D 65 01 00 15 28 4C 6A 61 76 61 2F 6C 61
6E 67 2F 53 74 72 69 6E 67 3B 29 56 01 00 0A 53
6F 75 72 63 65 46 69 6C 65 01 00 0F 55 73 65 72
45 6E 74 69 74 79 2E 6A 61 76 61 0C 00 07 00 08
0C 00 05 00 06 01 00 1E 63 6F 6D 2F 6A 61 72 79
65 2F 6A 61 76 61 61 73 69 73 74 2F 55 73 65 72
45 6E 74 69 74 79 01 00 10 6A 61 76 61 2F 6C 61
6E 67 2F 4F 62 6A 65 63 74 00 21 00 03 00 04 00
00 00 01 00 02 00 05 00 06 00 00 00 03 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 03 00 0B 00 00 00 0C 00 01
00 00 00 05 00 0C 00 0D 00 00 00 01 00 0E 00 0F
00 01 00 09 00 00 00 2F 00 01 00 01 00 00 00 05
2A B4 00 02 B0 00 00 00 02 00 0A 00 00 00 06 00
01 00 00 00 08 00 0B 00 00 00 0C 00 01 00 00 00
05 00 0C 00 0D 00 00 00 01 00 10 00 11 00 01 00
09 00 00 00 3E 00 02 00 02 00 00 00 06 2A 2B B5
00 02 B1 00 00 00 02 00 0A 00 00 00 0A 00 02 00
00 00 0C 00 05 00 0D 00 0B 00 00 00 16 00 02 00
00 00 06 00 0C 00 0D 00 00 00 00 00 06 00 05 00
06 00 01 00 01 00 12 00 00 00 02 00 13
javap -c -v Class文件反编译后效果
minor version: 0
major version: 52
Constant pool:
const #1 = Method #4.#20; // java/lang/Object."":()V
const #2 = Field #3.#21; // com/jarye/javaasist/UserEntity.userName:Ljava/lang/String;
const #3 = class #22; // com/jarye/javaasist/UserEntity
const #4 = class #23; // java/lang/Object
const #5 = Asciz userName;
const #6 = Asciz Ljava/lang/String;;
const #7 = Asciz ;
const #8 = Asciz ()V;
const #9 = Asciz Code;
const #10 = Asciz LineNumberTable;
const #11 = Asciz LocalVariableTable;
const #12 = Asciz this;
const #13 = Asciz Lcom/jarye/javaasist/UserEntity;;
const #14 = Asciz getUserName;
const #15 = Asciz ()Ljava/lang/String;;
const #16 = Asciz setUserName;
const #17 = Asciz (Ljava/lang/String;)V;
const #18 = Asciz SourceFile;
const #19 = Asciz UserEntity.java;
const #20 = NameAndType #7:#8;// "":()V
const #21 = NameAndType #5:#6;// userName:Ljava/lang/String;
const #22 = Asciz com/jarye/javaasist/UserEntity;
const #23 = Asciz java/lang/Object;
{
public com.jarye.javaasist.UserEntity();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/jarye/javaasist/UserEntity;
public java.lang.String getUserName();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: getfield #2; //Field userName:Ljava/lang/String;
4: areturn
LineNumberTable:
line 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/jarye/javaasist/UserEntity;
public void setUserName(java.lang.String);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: aload_1
2: putfield #2; //Field userName:Ljava/lang/String;
5: return
LineNumberTable:
line 12: 0
line 13: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/jarye/javaasist/UserEntity;
0 6 1 userName Ljava/lang/String;
}
使用jclasslib插件查看效果
打开idea 中的settings > plugins 搜索 jclasslib 插件 进行安装 重启生效
重启后点击view > 选择show bytecode with jclasslib
Class文件字节码结构组织示意图
Class文件整体结构说明
ClassFile {
u4 magic; //java的Class文件的标志,头四个字节固定为"CA FE BA BE"
u2 minor_version;//Class 的小版本号 "00 00"
u2 major_version;//Class 的大版本号 "00 34"转为十进制为52,即jdk8版本
u2 constant_pool_count;//常量池的数量 "00 18"十进制为24,参考javap反编译中的(const #23,其中0位虚拟机默认)
cp_info constant_pool[constant_pool_count-1];//常量池
u2 access_flags;//Class 的访问标记
u2 this_class;//当前类
u2 super_class;//父类
u2 interfaces_count;//接口
u2 interfaces[interfaces_count];//一个类可以实现多个接口
u2 fields_count;//Class 文件的字段属性
field_info fields[fields_count];//一个类会可以有个字段
u2 methods_count;//Class 文件的方法数量
method_info methods[methods_count];//一个类可以有个多个方法
u2 attributes_count;//此类的属性表中的属性数
attribute_info attributes[attributes_count];//属性表集合
}
tips:u后面代码字节码位数,字节码文件中相邻两位"0A"代表1个字节码
常量池中的字面量与符号引用
类 型 | 标 志 | 描 述 |
---|---|---|
CONSTANT_Utf8_info | 1(后2个字节是长度) | UTF-8编码的字符串 |
CONSTANT_Integer_info | 3 | 整型字面量 |
CONSTANT_Float_info | 4 | 浮点型字面量 |
CONSTANT_Long_info | 5 | 长整形字面量 |
CONSTANT_Double_info | 6 | 双精度浮点型字面量 |
CONSTANT_Class_info | 7(3个字节) | 类或接口的符号引用 |
CONSTANT_String_info | 8 | 字符串类型字面量 |
CONSTANT_Fieldref_info | 9(5个字节) | 字段的符号引用 |
CONSTANT_Methodref_info | 10(5个字节) | 方法的符号引用 |
CONSTANT_InterfaceMethodref_info | 11 | 接口的方法符号引用 |
CONSTANT_NameAndType_info | 12 | 字段或方法的部分符号引用 |
CONSTANT_MethodHandle_info | 15 | 表示方法句柄 |
CONSTANT_MethodType_info | 16 | 标识方法类型 |
CONSTANT_InvokeDynamic_info | 18 | 表示一个动态方法调用点 |
类或接口的访问标志
名称 | 值 | 备注 |
---|---|---|
ACC_PUBLIC | 0x0001 | 表示访问权限为public,可以从本包外访问 |
ACC_FINAL | 0x0010 | 表示由final修饰,不允许有子类 |
ACC_SUPER | 0x0020 | 较为特殊,表示动态绑定直接父类,见下面的解释 |
ACC_INTERFACE | 0x0200 | 表示接口,非类 |
ACC_ABSTRACT | 0x0400 | 表示抽象类,不能实例化 |
ACC_SYNTHETIC | 0x1000 | 表示由synthetic修饰,不在源代码中出现 |
ACC_ANNOTATION | 0x2000 | 表示是annotation类型 |
ACC_ENUM | 0x4000 | 表示是枚举类型 |
ACC_PRIVATE | 0X0002 | 表示私有 |
字段属性表结构
field_info {
u2 access_flags;// 字段的作用域( public , private , protected 修饰符),是实例变量还是类变量( static 修饰符),可否被序列化(transient 修饰符),可变性(final),可见性(volatile 修饰符,是否强制从主内存读写)。
u2 name_index; // 对常量池的引用,表示的字段的名称;
u2 descriptor_index;// 对常量池的引用,表示字段和方法的描述符;
u2 attributes_count;// 一个字段还会拥有一些额外的属性,attributes_count 存放属性的个数;
attribute_info attributes[attributes_count]; //具体的属性内容
}
字段属性access_flags 表
名称 | 值 | 备注 |
---|---|---|
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_TRANSIENT | 0x0080 | 序列化 |
ACC_SYNTHETIC | 0x1000 | 方法在源文件中不出现,由编译器产生 |
ACC_ENUM | 0x4000 | 枚举类型 |
方法表结构
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
方法access_flags 表
名称 | 值 | 备注 |
---|---|---|
ACC_PUBLIC | 0x0001 | public,方法可以从包外访问 |
ACC_PRIVATE | 0x0002 | private,方法只能本类中访问 |
ACC_PROTECTED | 0x0004 | protected,方法在自身和子类可以访问 |
ACC_STATIC | 0x0008 | static,静态方法 |
ACC_FINAL | 0x0010 | final,方法不能被重写(覆盖) |
ACC_SYNCHRONIZED | 0x0020 | synchronized,方法由管程同步 |
ACC_BRIDGE | 0x0040 | bridge,方法由编译器产生 |
ACC_VARARGS | 0x0080 | 表示方法带有变长参数 |
ACC_NATIVE | 0x0100 | native,方法引用非 java 语言的本地方法 |
ACC_ABSTRACT | 0x0400 | abstract,方法没有具体实现 |
ACC_STRICT | 0x0800 | strictfp,方法使用 FP-strict 浮点格式 |
ACC_SYNTHETIC | 0x1000 | 方法在源文件中不出现,由编译器产生 |
属性结构
Code_attribute {
u2 attribute_name_index(2); //常量池中的uft8类型的索引,值固定为”Code“
u4 attribute_length(4); //属性值长度,为整个属性表长度-6
u2 max_stack; //操作数栈的最大深度值,jvm运行时根据该值分配栈帧
u2 max_locals; //局部变量表最大存储空间,单位是slot
u4 code_length; // 字节码指令的个数
u1 code[code_length]; // 具体的字节码指令
u2 exception_table_length; //异常的个数
{ u2 start_pc;
u2 end_pc;
u2 handler_pc; //当字节码在[start_pc, end_pc)区间出现catch_type或子类,则转到handler_pc行继续处理。
u2 catch_type; //当catch_type=0,则任意异常都需转到handler_pc处理
} exception_table[exception_table_length]; //具体的异常内容
u2 attributes_count; //属性的个数
attribute_info attributes[attributes_count]; //具体的属性内容
}
其中slot为局部变量中的最小单位。boolean、 byte、 char、 short、 float、 reference和 returnAddress 等小于等于32位的用一个slot表示,double,long这些大于32位的用2个slot表示。
为什么class文件需要通过2进制排列?
目的就是为了能够压缩,减少类加载到元空间存储的大小,避免fullGC的问题。
为什么一个类最多只能实现65535个接口?
一个类的最大接口数是有2个字节组成,使用16进制最多只支持FFFF,十进制为65535个接口。
u2 interfaces[interfaces_count];//一个类可以实现多个接口
项目中使用工具:十六进制和ASCII 在线转换器、进制转换工具
相关文章链接:
<<
<<<如何自定义注解
<<<十大经典排序算法汇总-动画演示
<<