高效学习博客:
Class类文件结构: https://www.cnblogs.com/wade-luffy/p/5929325.html
Java Class文件结构解析 及 实例分析验证 : https://blog.csdn.net/tjiyu/article/details/53870153
Class文件中的常量池详解(上): https://blog.csdn.net/wangtaomtk/article/details/52267548
官方java class文件结构文档:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
可以下载个010Editor,打开class文件后会提示下载解析class文件脚本,之后就很方便,每一项都清清楚楚是干嘛的。
http://www.sweetscape.com/download/010editor/
一.Class文件整体结构:
全在这张图中了,再结合后面解析二进制文件字节码的例子,基本就掌握了大概的结构规则,当然这只是简单的解析。
本图的draw.io源文件在百度盘中下载,可再自行添加修改:
链接: https://pan.baidu.com/s/1FMPUeBGaCKFZXEh-M8a6vA 提取码: nhwf
Class文件中只有两类数据类型:
- 无符号数:
无符号数属于基本的数据类型,以u1、u2、u4、u8来表示一个字节、两个字节...的无符号数;
无符号数用来描述数字、索引引用、数量值或UTF-8编码构成的字符串值。 - 表:
表是由多个无符号数或其他表作为数据项构成的复合数据类型,一般以"_info"结尾
表中的项长度不固定
主要结构类型:
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];
}
讲解:
类型 | 名称 | 数量 | 说明 |
---|---|---|---|
u4 | magic | 1 | 魔数:确定一个文件是否是Class文件 |
u2 | minor_version | 1 | Class文件的次版本号 |
u2 | major_version | 1 | Class文件的主版本号:一个JVM实例只能支持特定范围内版本号的Class文件(可以向下兼容)。 |
u2 | constant_pool_count | 1 | 常量表数量 |
cp_info | constant_pool | constant_pool_count-1 | 常量池:以理解为Class文件的资源仓库,后面的其他数据项可以引用常量池内容 |
u2 | access_flags | 1 | 类的访问标志信息:用于表示这个类或者接口的访问权限及基础属性。 |
u2 | this_class | 1 | 指向当前类的常量索引:用来确定这个类的全限定名。 |
u2 | super_class | 1 | 指向当父类的常量索引:用来确定这个类的父类的全限定名。 |
u2 | interfaces_count | 1 | 接口的数量 |
u2 | interfaces | interfaces_count | 指向接口的常量索引:用来描述这个类实现了哪些接口。 |
u2 | fields_count | 1 | 字段表数量 |
field_info | fields | fields_count | 字段表集合:描述当前类或接口声明的所有字段。 |
u2 | methods_count | 1 | 方法表数量 |
method_info | methods | methods_count | 方法表集合:只描述当前类或接口中声明的方法,不包括从父类或父接口继承的方法。 |
u2 | attributes_count | 1 | 属性表数量 |
attributes_info | attributes | attributes_count | 属性表集合:用于描述某些场景专有的信息,如字节码的指令信息等等。 |
二.举个例子
1. 如下class文件:**
/home/chengang/IdeaProjects/JavaTest/src/Computer.java
public class Computer {
final String TAG = "Log";
private String mName;
int mPrice;
public Computer(String mModel, int mPrice) {
this.mName = mModel;
this.mPrice = mPrice;
System.out.println(TAG + " new Computer()");
}
public String getName() {
return mName;
}
public int getPrice() {
return mPrice;
}
}
2.生成如下字节码:**
用vim打开文件并二进制查看:
vim /home/chengang/IdeaProjects/JavaTest/out/production/JavaTest/Computer.class
:%!xxd
具体可参考:
00000000: cafe babe (魔数u4) 0000 0034(版本号u2+u2) 0032(cp_count,常量池50个,包含一个索引0的) 0a(tag:0a=10 是Methodref)00 0a(class_index:0a=10,常量池中第10项)00 1f(name_and_type_index:001f=31,常量池中第31项)08(tag:08=8 是String) .......4.2......
00000010: 0020(string_index:0020=32,常量池第32项“Log”) 09(tag:09=9 是Fieldref)00 07(class_index:07=7,常量池中第7项,“Computer”)00 21(name_type_index:0021=33,常量池中第33项,“TAG:Ljava/lang/String;”,之后类似)09 0007 0022 0900 0700 . ....!...."....
00000020: 2309 0024 0025 0700 2608 0027 0a00 2800 #..$.%..&..'..(.
00000030: 2907 002a 0100 0354 4147 0100 124c 6a61 )..*...TAG...Lja
00000040: 7661 2f6c 616e 672f 5374 7269 6e67 3b01 va/lang/String;.
00000050: 000d 436f 6e73 7461 6e74 5661 6c75 6501 ..ConstantValue.
00000060: 0005 6d4e 616d 6501 0006 6d50 7269 6365 ..mName...mPrice
00000070: 0100 0149 0100 063c 696e 6974 3e01 0016 ...I...<init>...
00000080: 284c 6a61 7661 2f6c 616e 672f 5374 7269 (Ljava/lang/Stri
00000090: 6e67 3b49 2956 0100 0443 6f64 6501 000f ng;I)V...Code...
000000a0: 4c69 6e65 4e75 6d62 6572 5461 626c 6501 LineNumberTable.
000000b0: 0012 4c6f 6361 6c56 6172 6961 626c 6554 ..LocalVariableT
000000c0: 6162 6c65 0100 0474 6869 7301 000a 4c43 able...this...LC
000000d0: 6f6d 7075 7465 723b 0100 066d 4d6f 6465 omputer;...mMode
000000e0: 6c01 0007 6765 744e 616d 6501 0014 2829 l...getName...()
000000f0: 4c6a 6176 612f 6c61 6e67 2f53 7472 696e Ljava/lang/Strin
00000100: 673b 0100 0867 6574 5072 6963 6501 0003 g;...getPrice...
00000110: 2829 4901 000a 536f 7572 6365 4669 6c65 ()I...SourceFile
00000120: 0100 0d43 6f6d 7075 7465 722e 6a61 7661 ...Computer.java
00000130: 0c00 1100 2b01 0003 4c6f 670c 000b 000c ....+...Log.....
00000140: 0c00 0e00 0c0c 000f 0010 0700 2c0c 002d ............,..-
00000150: 002e 0100 0843 6f6d 7075 7465 7201 0012 .....Computer...
00000160: 4c6f 6720 6e65 7720 436f 6d70 7574 6572 Log new Computer
00000170: 2829 0700 2f0c 0030 0031 0100 106a 6176 ()../..0.1...jav
00000180: 612f 6c61 6e67 2f4f 626a 6563 7401 0003 a/lang/Object...
00000190: 2829 5601 0010 6a61 7661 2f6c 616e 672f ()V...java/lang/
000001a0: 5379 7374 656d 0100 036f 7574 0100 154c System...out...L
000001b0: 6a61 7661 2f69 6f2f 5072 696e 7453 7472 java/io/PrintStr
000001c0: 6561 6d3b 0100 136a 6176 612f 696f 2f50 eam;...java/io/P
000001d0: 7269 6e74 5374 7265 616d 0100 0770 7269 rintStream...pri
000001e0: 6e74 6c6e 0100 1528 4c6a 6176 612f 6c61 ntln...(Ljava/la
000001f0: 6e67 2f53 7472 696e 673b 2956 (在这之前为常量池)0021(类access_flag:0021=0x0020&0x001,查表代表ACC_SUPER和ACC_PUBLIC) 0007(this_class:0007=7,常量池第7项,“Computer”) ng/String;)V.!..
00000200: 000a(super_class:000a=10,常量池第10项,“java/lang/Object”,java中所有基类都默认有一个父类Object类) 0000(interfaces_count:0000=0,无接口,因此无后面的interface部分) 0003(fields_count:0003=3,代表有3个字段,之后有三个field_info,字段表从此开始) 0010(字段access_flag:0x0010查字段的访问标志表为ACC_FINAL类型,代表着final修饰符) 000b(name_index:000b=11,常量池第11项,“TAG”) 000c(descriptor_index:000c=12,字段描述符,常量池第12项,“Ljava/lang/String;”) 0001(attributes_count:0001=1,后面有一个属性项) 000d(attribute_name_index:000d=13,常量池第13项,“ConstantValue”) ................
00000210: 0000 0002(u4 attribute_length:2) 0002(constantvalue_index:0002=2,常量池第2项,“Log”) 0002(第2个字段的access_flag:0002=2,0x0002查表为ACC_PRIVATE,即private修饰符) 000e(name_index:000e=14,常量池第14项,“mName”) 000c(descriptor_index:000c=12,常量池第12项,“Ljava/lang/String;”) 0000(attributes_count:0000=0,后面没有属性项) 0000(第三个字段的access_flag,没有使用需要设置为0) ................
00000220: 000f(name_index:000f=15,常量池第15项,“mPrice”) 0010(descriptor_index:0010=16,常量池项中的第16项,“I”代表Int类型) 0000(attributes_count:0,后面无属性项,字段表至此结束) 0003(methods_count=3代表后面有三个method_info,方法表从此处开始) 0001(方法的access_flag:0001=0x0001,查询方法项的access_flag为ACC_PUBLIC) 0011(name_index:0011=17,常量池中的第17项“<init>”,代表着实例构造器,如果代码中有定义构造函数,在解析的语法分析阶段被重命名为<init>()) 0012(descriptor_index:0012=18,常量池中的第18项,“(Ljava/lang/String;I)V”,代表着void类型的方法,有String和int两个类型的参数) 0001(attribute_count:0001=1,后面有一个属性项) ................
00000230: 0013(attribute_name_index:0013=19,常量表中的第19项,“Code”,code属性,再根据code属性的组成格式,依次解析后面的每一个字节的含义) 0000 006f 0002 0003 0000 001d 2ab7 .....o........*.
00000240: 0001 2a12 02b5 0003 2a2b b500 042a 1cb5 ..*.....*+...*..
00000250: 0005 b200 0612 08b6 0009 b100 0000 0200 ................
00000260: 1400 0000 1a00 0600 0000 0600 0400 0200 ................
00000270: 0a00 0700 0f00 0800 1400 0900 1c00 0a00 ................
00000280: 1500 0000 2000 0300 0000 1d00 1600 1700 .... ...........
00000290: 0000 0000 1d00 1800 0c00 0100 0000 1d00 ................
000002a0: 0f00 1000 0200 0100 1900 1a00 0100 1300 ................
000002b0: 0000 2f00 0100 0100 0000 052a b400 04b0 ../........*....
000002c0: 0000 0002 0014 0000 0006 0001 0000 000d ................
000002d0: 0015 0000 000c 0001 0000 0005 0016 0017 ................
000002e0: 0000 0001 001b 001c 0001 0013 0000 002f .............../
000002f0: 0001 0001 0000 0005 2ab4 0005 ac00 0000 ........*.......
00000300: 0200 1400 0000 0600 0100 0000 1100 1500 ................
00000310: 0000 0c00 0100 0000 0500 1600 1700 0000 ................
00000320: 0100 1d00 0000 0200 1e .........
可以使用010Editor打开class文件,更加清晰明了:
3.Javap反解析结构图**
javap反编译工具,可以根据class字节码反解析出当前类对应的code区(汇编指令)、本地变量表、异常表和代码行偏移量映射表、常量池等等信息:
chengang@mi:~$ javap -v '/home/chengang/IdeaProjects/JavaTest/out/production/JavaTest/Computer.class'
Classfile /home/chengang/IdeaProjects/JavaTEst/out/production/JavaTest/Computer.class
Last modified Apr 26, 2019; size 809 bytes
MD5 checksum 561774586f9e1d34a2e35a7617d17f5c
Compiled from "Computer.java"
public class Computer
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #10.#31 // java/lang/Object."<init>":()V
#2 = String #32 // Log
#3 = Fieldref #7.#33 // Computer.TAG:Ljava/lang/String;
#4 = Fieldref #7.#34 // Computer.mName:Ljava/lang/String;
#5 = Fieldref #7.#35 // Computer.mPrice:I
#6 = Fieldref #36.#37 // java/lang/System.out:Ljava/io/PrintStream;
#7 = Class #38 // Computer
#8 = String #39 // Log new Computer()
#9 = Methodref #40.#41 // java/io/PrintStream.println:(Ljava/lang/String;)V
#10 = Class #42 // java/lang/Object
#11 = Utf8 TAG
#12 = Utf8 Ljava/lang/String;
#13 = Utf8 ConstantValue
#14 = Utf8 mName
#15 = Utf8 mPrice
#16 = Utf8 I
#17 = Utf8 <init>
#18 = Utf8 (Ljava/lang/String;I)V
#19 = Utf8 Code
#20 = Utf8 LineNumberTable
#21 = Utf8 LocalVariableTable
#22 = Utf8 this
#23 = Utf8 LComputer;
#24 = Utf8 mModel
#25 = Utf8 getName
#26 = Utf8 ()Ljava/lang/String;
#27 = Utf8 getPrice
#28 = Utf8 ()I
#29 = Utf8 SourceFile
#30 = Utf8 Computer.java
#31 = NameAndType #17:#43 // "<init>":()V
#32 = Utf8 Log
#33 = NameAndType #11:#12 // TAG:Ljava/lang/String;
#34 = NameAndType #14:#12 // mName:Ljava/lang/String;
#35 = NameAndType #15:#16 // mPrice:I
#36 = Class #44 // java/lang/System
#37 = NameAndType #45:#46 // out:Ljava/io/PrintStream;
#38 = Utf8 Computer
#39 = Utf8 Log new Computer()
#40 = Class #47 // java/io/PrintStream
#41 = NameAndType #48:#49 // println:(Ljava/lang/String;)V
#42 = Utf8 java/lang/Object
#43 = Utf8 ()V
#44 = Utf8 java/lang/System
#45 = Utf8 out
#46 = Utf8 Ljava/io/PrintStream;
#47 = Utf8 java/io/PrintStream
#48 = Utf8 println
#49 = Utf8 (Ljava/lang/String;)V
{
final java.lang.String TAG;
descriptor: Ljava/lang/String;
flags: ACC_FINAL
ConstantValue: String Log
int mPrice;
descriptor: I
flags:
public Computer(java.lang.String, int);
descriptor: (Ljava/lang/String;I)V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=3
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String Log
7: putfield #3 // Field TAG:Ljava/lang/String;
10: aload_0
11: aload_1
12: putfield #4 // Field mName:Ljava/lang/String;
15: aload_0
16: iload_2
17: putfield #5 // Field mPrice:I
20: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
23: ldc #8 // String Log new Computer()
25: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: return
LineNumberTable:
line 6: 0
line 2: 4
line 7: 10
line 8: 15
line 9: 20
line 10: 28
LocalVariableTable:
Start Length Slot Name Signature
0 29 0 this LComputer;
0 29 1 mModel Ljava/lang/String;
0 29 2 mPrice I
public java.lang.String getName();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #4 // Field mName:Ljava/lang/String;
4: areturn
LineNumberTable:
line 13: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LComputer;
public int getPrice();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #5 // Field mPrice:I
4: ireturn
LineNumberTable:
line 17: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LComputer;
}
SourceFile: "Computer.java"
三.Class文件结构表项详细及重点
字段描述符中基本类型:
字符 | 类型 | 含义 |
---|---|---|
B | byte | 有符号字节型数 |
C | char | Unicode 字符,UTF-16 编码 |
D | double | 双精度浮点数 |
F | float | 单精度浮点数 |
I | int | 整型数 |
J | long | 长整数 |
S | short | 有符号短整数 |
Z | boolean | 布尔值:true/false |
L Classname; | reference | 一个名为<Classname>的实例 |
[ | reference | 一个一维数组 |
V | void | void返回值(其实不属于基本类型,而是VoidDescriptor) |
1.魔数
Class文件开始是4个字节定义为魔数(Magic Number);
唯一作用:确定一个文件是否是Class文件
2.Class文件版本
魔数之后的4个字节标识版本号,即minor_version为0,major_version为52(0034对应的十进制),版本为52.0(符合JDK8)
各个版本的对应关系:
JDK版本号 | Class版本号 | 16进制 |
---|---|---|
1.1 | 45.0 | 00 00 00 2D |
1.2 | 46.0 | 00 00 00 2E |
1.3 | 47.0 | 00 00 00 2F |
1.4 | 48.0 | 00 00 00 30 |
1.5 | 49.0 | 00 00 00 31 |
1.6 | 50.0 | 00 00 00 32 |
1.7 | 51.0 | 00 00 00 33 |
1.8 | 52.0 | 00 00 00 34 |
3.常量池
常量池可以理解为Class文件的资源仓库,后面的其他数据项可以引用常量池内容;
常量池每一项都是一个表包含Class文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其它常量;
主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References);
常量池里的没一项都有如下格式:
//常量池项的通用格式
cp_info {
u1 tag;// 1byte 标志位,标识了info[]项的内容,即 info[]属于什么类型
u1 info[];
}
JDK 1.8 有14中常量类型及各自组成格式:
Constant Type | Value | 占用字节数 | 组成部分 | comments |
---|---|---|---|---|
CONSTANT_Class | 7 | 3 | u1 tag; u2 name_index; |
|
CONSTANT_Fieldref | 9 | 5 | u1 tag; u2 class_index; u2 name_and_type_index; |
|
CONSTANT_Methodref | 10 | 5 | u1 tag; u2 class_index; u2 name_and_type_index; |
|
CONSTANT_InterfaceMethodref | 11 | 5 | u1 tag; u2 class_index; u2 name_and_type_index;` |
|
CONSTANT_String | 8 | 3 | u1 tag; u2 string_index; |
|
CONSTANT_Integer | 3 | 5 | u1 tag; u4 bytes |
|
CONSTANT_Float | 4 | 5 | u1 tag; u4 bytes;` |
|
CONSTANT_Long | 5 | 9 | u1 tag; u4 high_bytes; u4 low_bytes; |
占用2个常量表项空间 |
CONSTANT_Double | 6 | 9 | u1 tag; u4 high_bytes; u4 low_bytes; |
占用2个常量表项空间 |
CONSTANT_NameAndType | 12 | 5 | u1 tag; u2 name_index; u2 descriptor_index; |
|
CONSTANT_Utf8 | 1 | 1+2+length | u1 tag; u2 length; u1 bytes[length]; |
|
CONSTANT_MethodHandle | 15 | 4 | u1 tag; u1 reference_kind; u2 reference_index; |
|
CONSTANT_MethodType | 16 | 3 | u1 tag; u2 descriptor_index; |
|
CONSTANT_InvokeDynamic | 18 | 5 | u1 tag; u2 bootstrap_method_attr_index; u2 name_and_type_index; |
4.类的访问标志
用于表示这个类或者接口的访问权限及基础属性;
可以用16位掩码标志,目前只使用8种(JDK1.5增加后面三种),没使用的需要设置为0;
类的access_flags表:
标记名 | 值 | 含义 |
---|---|---|
ACC_PUBLIC | 0x0001 | 可以被包的类外访问。 |
ACC_FINAL | 0x0010 | 不允许有子类。 |
ACC_SUPER | 0x0020 | 当用到 invokespecial 指令时,需要特殊处理的父类方法。 |
ACC_INTERFACE | 0x0200 | 标识定义的是接口而不是类。 |
ACC_ABSTRACT | 0x0400 | 不能被实例化。 |
ACC_SYNTHETIC | 0x1000 | 标识并非 Java 源码生成的代码。 |
ACC_ANNOTATION | 0x2000 | 标识注解类型 |
ACC_ENUM | 0x4000 | 标识枚举类型 |
5.当前类索引
u2
指向当前类的在常量池项中的该类的索引
6.父类索引
u2
指向当前类的父类在常量池项中的该类的索引
用来确定这个类的父类的全限定名;
因为Java语言不允许多生继承,所以父类索引只有一个;并且除java.lang.Object外,其他所有类的父类索引都不能为0;
对于接口来说,索引指向的项必须为代表java.lang.Object的CONSTANT_Class_info类型常量;
7.接口索引集合
size | 项目 |
---|---|
u2 | interfaces_count |
u2 | interfaces |
implements(接口extends)后实现的按顺序从左到右排列在接口索引集合;
如果没有实现任何接口,interfaces_count为0,后面不再有interfaces[interfaces_count];
8.字段表 Fields
字段表集合描述当前类或接口声明的所有字段;
field_info用于表示当前类或接口中某个字段的完整描述,包括类字段(static字段)或实例字段,不包括局部变量,但不包括从父类或父接口继承的部分字段;
对内部类,编译器可能自动添加对外部类实例的字段;
基本组成:
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
access_flag:
是用于定义字段被访问权限和基础属性的掩码标志;
和前面类的访问标志一样,没使用的需要设置为0;
有些标记是互斥的,如不能同时设置标志 ACC_FINAL 和 ACC_VOLATILE;
字段的access_flag表:
Flag Name | Value | Interpretation |
---|---|---|
ACC_PUBLIC |
0x0001 | Declared public ; may be accessed from outside its package. |
ACC_PRIVATE |
0x0002 | Declared private ; usable only within the defining class. |
ACC_PROTECTED |
0x0004 | Declared protected ; may be accessed within subclasses. |
ACC_STATIC |
0x0008 | Declared static . |
ACC_FINAL |
0x0010 | Declared final ; never directly assigned to after object construction (JLS §17.5). |
ACC_VOLATILE |
0x0040 | Declared volatile ; cannot be cached. |
ACC_TRANSIENT |
0x0080 | Declared transient ; not written or read by a persistent object manager. |
ACC_SYNTHETIC |
0x1000 | Declared synthetic; not present in the source code. |
ACC_ENUM |
0x4000 | Declared as an element of an enum . |
attribute_info在后面详细展开
9.方法表
methods[]数组只描述当前类或接口中声明的方法;
包括实例方法、类方法、实例初始化方法方法和类或接口初始化方法方法;但不包括从父类或父接口继承的方法;
可能存在编译自动添加的方法,如类构造器"<clinit>"和实例构造器"<init>";
method_info用于表示当前类或接口中某个方法的完整描述;
如attributes[]中可能存在"Code"属性,表示方法逻辑代码编译后的字节码指令;
method_info {
u2 access_flags;//用于定义当前方法的访问权限和基本属性的掩码标志;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
access_flags:
和前面类的访问标志一样,没使用的需要设置为0;
有些标记是互斥的,如不能同时设置标志 ACC_FINAL 和 ACC_ABSTRACT;
方法项的access_flags表:
Flag Name | Value | Interpretation |
---|---|---|
ACC_PUBLIC |
0x0001 | Declared public ; may be accessed from outside its package. |
ACC_PRIVATE |
0x0002 | Declared private ; accessible only within the defining class. |
ACC_PROTECTED |
0x0004 | Declared protected ; may be accessed within subclasses. |
ACC_STATIC |
0x0008 | Declared static . |
ACC_FINAL |
0x0010 | Declared final ; must not be overridden (§5.4.5). |
ACC_SYNCHRONIZED |
0x0020 | Declared synchronized ; invocation is wrapped by a monitor use. |
ACC_BRIDGE |
0x0040 | A bridge method, generated by the compiler. |
ACC_VARARGS |
0x0080 | Declared with variable number of arguments. |
ACC_NATIVE |
0x0100 | Declared native ; implemented in a language other than Java. |
ACC_ABSTRACT |
0x0400 | Declared abstract ; no implementation is provided. |
ACC_STRICT |
0x0800 | Declared strictfp ; floating-point mode is FP-strict. |
ACC_SYNTHETIC |
0x1000 | Declared synthetic; not present in the source code. |
attribute_info在后面详细展开
10.属性表
在Class文件的 ClassFile结构、字段表、方法表中都可以存储放自己的属性表集合,所以并不像最前面那Class文件结构那么直观,即属性不都是放在Class文件的最后;
属性表的通用格式:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
不同属性的info是不同的,即attribute_name_index对应的类型有特定的属性格式
具体在 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.2 中,不多赘述。