在接口索引之后的就是字段表的集合
我有关字段表的字节为00 01,00 00,00 06,00 07,00 00,分别为,集合大小,字段标志位,字段名,字段类型,属性计数器,请大家两个字节两个字节来看,第一个字节块(即前两个字节,以此类推(_)),声明了字段表的大小,00 01,即一个字段,第二个字节块声明了,第一个字段的的标志,意思如下图表格所示
标志名称 | 值 | 标记含义 |
---|---|---|
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 | 标记是否为transient修饰 |
acc_synthetic | 0x1000 | 标记是否为编译器产生 |
acc_enum | 0x0400 | 标记是否为enum |
参照表格很容易就能发现,第一个字段什么标志也没有,是00 00,继续看第三个字节块,00 06,它指向该字段的名字,打开Javap
该字段叫作i,第四个字节块指向该字段的类型,为I,标识符(就是那个I啦)与含义的关系如下表
标识符 | 含义 |
---|---|
B | 基本数据类型byte |
C | 基本数据类型char |
D | 基本数据类型double |
F | 基本数据类型float |
I | 基本数据类型int |
J | 基本数据类型long |
S | 基本数据类型short |
Z | 基本数据类型boolean |
V | 特殊数据类型void |
L | 对象类型,如object |
也就是说这是一个没有任何修饰的叫i的int值,最后一个字节块为00 00,表示他没有附带的其他属性,如果i为final,static修饰,此处可能存在其他属性
方法表与字段表结构相似
前4个代码块依然为,集合大小,字段标志位,字段名,字段类型,但方法表中有一个非常重要的属性,code属性,这便是方法转换后的字节码,话不多说,直接开始分析,00 03,00 01,00 08,00 09,00 01,00 0A,00 00 00 38.。。。,00 03代表这个类中共有三个方法,00 01代表第一个方法的访问标志,标记这个方法是一个public修饰的,00 08为方法名,查看Javap可知方法名为init,,00 09表示描述符索引,即()v,即不需要传参,返回值为void,综合一下,这个类是一个叫init的public方法,不需要传参,且没有返回值,即public void init(),00 01代表方法有一个属性,即code属性,查看Javap,00 0A的确指向code,00 00 00 38表示code属性有38个字节,由此也可以得出,Java中方法的最大字节长度为2562890625,当然实际上Java虚拟机明确规定了方法的最大字节码为65535,当然这和我们普通程序员没什么关系,如果不是刻意去为难jvm,基本上也不会遇到这个问题(●ˇ∀ˇ●),接下来我们看看这个code属性到底是什么意思,照例javap编译一下字节码
得到编译后的code指令
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #2 // Field i:I
9: return
我们一句一句分析,前两句是连在一起的,第一句的意思是将第一个对象引用的局部表变量加载到栈顶,由于这里的方法不为static修饰,这里指的是this,即当前方法的的实例的引用,invokespecial #1表示调用实例构造器方法并赋值给栈顶对象,即调用init方法并赋值给this,用Java描述即为this=testclass.init();,即初始化,4,5,6同样是连接起来的,4同上文一样,等效为将this加载至栈顶,,而5表示将一个int型的变量推送到栈顶,6表示给指定类中的实例赋值,在这里指TestClass的属性i,实际执行步骤是this先入栈,随后1入栈,最后putfield让他们一起出栈,并将this,i赋值为1,有时间我再把jvm字节码操作专门写一段吧,先溜了ε=ε=ε=┏(゜ロ゜;)┛