04、字段表集合
字段表用来描述接口或者类中声明的变量,包括类变量和成员变量,但不包含声明在方法中局部变量。
字段的修饰符一般有:
访问权限修饰符,比如 public private protected
静态变量修饰符,比如 static
final 修饰符
并发可见性修饰符,比如 volatile
序列化修饰符,比如 transient
然后是字段的类型(可以是基本数据类型、数组和对象)和名称。
在 Main.class 字节码文件中,字段表的信息如下所示。
private int age;
descriptor: I
flags: (0x0002) ACC_PRIVATE
表明字段的访问权限修饰符为 private,类型为 int,名称为 age。
字段的访问标志和类的访问标志非常类似。
05、方法表集合
方法表用来描述接口或者类中声明的方法,包括类方法和成员方法,以及构造方法。方法的修饰符和字段略有不同,比如说 volatile 和 transient 不能用来修饰方法,再比如说方法的修饰符多了 synchronized、native、strictfp 和 abstract。
下面这部分为构造方法,返回类型为 void,访问标志为 public。
public com.itwanger.jvm.Main();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
来详细看一下其中 Code 属性。
Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: bipush 18 7: putfield #2 // Field age:I 10: return LineNumberTable: line 6: 0 line 7: 4 LocalVariableTable: Start Length Slot Name Signature 0 11 0 this Lcom/itwanger/jvm/Main;
stack 为最大操作数栈,Java 虚拟机在运行的时候会根据这个值来分配栈帧的操作数栈深度。
locals 为局部变量所需要的存储空间,单位为槽(slot),方法的参数变量和方法内的局部变量都会存储在局部变量表中。
args_size 为方法的参数个数。
为什么 stack 的值为 2,locals 的值为 1,args_size 的值为 1 呢? 默认的构造方法不是没有参数和局部变量吗?
这是因为有一个隐藏的 this 变量,只要不是静态方法,都会有一个当前类的对象 this 悄悄的存在着。这就解释了为什么 locals 和 args_size 的值为 1 的问题。那为什么 stack 的值为 2 呢?因为字节码指令 invokespecial(调用父类的构造方法进行初始化)会消耗掉一个当前类的引用,所以 aload_0 执行了 2 次,也就意味着操作数栈的大小为 2。
关于字节码指令,我们后面再详细介绍。
LineNumberTable,该属性的作用是描述源码行号与字节码行号(字节码偏移量)之间的对应关系。
LocalVariableTable,该属性的作用是描述帧栈中的局部变量与源码中定义的变量之间的关系。大家仔细看一下,就能看到 this 的影子了。
下面这部分为成员方法 getAge(),返回类型为 int,访问标志为 public。
public int getAge();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
理解了构造方法的 Code 属性后,再看 getAge() 方法的 Code 属性时,就很容易理解了。
Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #2 // Field age:I 4: ireturn LineNumberTable: line 9: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/itwanger/jvm/Main;
最大操作数栈为 1,局部变量所需要的存储空间为 1,方法的参数个数为 1,是因为局部变量只有一个隐藏的 this,并且字节码指令中只执行了一次 aload_0。
本来想着这一篇就彻底把 Java 字节码给结束掉,没想到还得再学习一下字节码指令,难顶!
其实学习就是这样,可以横向扩展,也可以纵向扩展。当我们初学编程的时候,特别想多学一点,属于横向扩展,当有了一定的编程经验后,想更上一层楼,就需要纵向扩展,不断深入地学,连根拔起,从而形成自己的知识体系。
无论是从十六进制的字节码角度,还是 jclasslib 图形化查看反编译后的字节码的角度,也或者是今天这样从 javap 反编译后的角度,都能窥探出一些新的内容来!
初学者一开始接触字节码的时候会感觉比较头大,没关系,我当初也是这样,随着时间的推移,经验的积累,慢慢就好了,越往深处钻,就越能体会到那种“技术我有,雄霸天下”的感觉~
说两句,马上秋招了,可以开始准备了。
一定记得刷一刷面试题,背一背八股文,要乖哦,千万不要抗拒!千万不要裸面,真的!其实私下里,很多学弟学妹们都向我哭诉过,说大厂的面试题太难了,有的题出的真的是万万没想到啊(狗头)。甚至有些中小厂的面试题都很难对答如流(他们的面试官可能看过我这份面试题库,哈哈哈),有了这份面试题库后,大家再也不用慌了!
V4.0 《JavaGuide 面试突击版》来啦!GitHub 上标星 98.1k,帮你成功上岸!
我是一直在悄悄打怪的二哥,希望能和同学们一起,变得更强,更秃(不不不,更帅),既然看到着了,就赏个三连吧,只收藏也不是不可以!
下期见~