一个方法的本地变量表this是何时被赋值的
这个插件是jclasslib
对于一个实例方法来说,本地变量表的0项一定是this。比如:
init方法和func方法的本地变量表。
那么this是什么时候被赋值的呢?
2020-10-30记录,当时自己这么写还是很准的,因为对于static方法本地变量表的第0项还真不是this
我们看一下new一个对象的字节码,java源代码如下
public class AppTest { private int i ; private String s = "aaa"; private static String cons = "bbb"; public AppTest(int p) { this.i = p; } public static String process(Integer i, Long l, String s) { int j = 6; int k = 4; int result = j + k; Long n = 5l; String t = "m"; return "1"; } public void func(int input) { i = input; } public void func2(int input) { i = input; } public static void main(String[] args) { // process(1,2L,"ss"); AppTest test = new AppTest(22); Integer i = 90; } }
0 new #10 <com/suning/mxz/AppTest> 3 dup 4 bipush 22 6 invokespecial #11 <com/suning/mxz/AppTest.<init>> 9 astore_1 10 bipush 90 12 invokestatic #12 <java/lang/Integer.valueOf> 15 astore_2 16 return
注意
invokespecial #11 <com/suning/mxz/AppTest.<init>> 我们解释一下invokespecial这个字节码指令
格式
invokespecial
indexbyte1
indexbyte2
编码
invokespecial = 183 (0xb7)
操作数栈
..., objectref, [arg1, [arg2 ...]]
也就是说
invokespecial ,至少有一个入参,是一个引用类型指向当前的对象 0 new #10 <com/suning/mxz/AppTest> 分配空间,并把得到的地址压入操作数栈 3 dup 把操作数栈栈顶拷贝一份,也就是现在的操作数栈有一个指向对象的指针了 4 bipush 22 把22压入操作数栈
紧接着就是调用
invokespecial #11 <com/suning/mxz/AppTest.<init>> 所以栈顶的两个操作数就弹出来了,作为invokespecial的入参
如果该方法不是native的,nargs个参数和objectref从栈中弹出,在当前JVM栈中为该方法创建一个新的栈帧。
Objectref和nargs个参数值连续存入新栈帧的局部变量表。
Objectref存入slot0,arg1存入slot1(或者,如果arg1为long或double类型,则占连续两个slot,为slot1,slot2),以此类推。
任何float类型的变量在存入局部变量表之前都会先进行值集转换。新栈帧成为当前栈帧,JVM PC设置为新方法的第一条指令,程序执行从该方法第一条指令继续。
也就是this的引用就是在调用 invokespecial 被赋值的
继续分析下该例子中其他的字节码指令
第9行的 astore_1
从oracle 官网上看
Store reference
into local variable 就是把一个引用对象赋值给本地变量表1号变量
1号变量就是test 正好对应这句代码
AppTest test = new AppTest(22);
astore 和 istore都是 复制操作,区别就是a表示的是引用类型,i表示整型
我们不妨再看看构造方法的字节码
public class AppTest { private int i = 55; private String s = "aaa"; private static String cons = "bbb"; public AppTest() { this.i = 66; }
0 aload_0 1 invokespecial #1 <java/lang/Object.<init>> 先执行Object的init 4 aload_0 5 bipush 55 7 putfield #2 <com/suning/mxz/AppTest.i> 10 aload_0 11 ldc #3 <aaa> 13 putfield #4 <com/suning/mxz/AppTest.s> 把成员变量i s都赋了值 16 aload_0 17 bipush 66 19 putfield #2 <com/suning/mxz/AppTest.i> 这里才是
public AppTest() {
this.i = 66;
}
22 return
aload_0
The <n> must be an index into the local variable array of the current frame (§2.6).
The local variable at <n> must contain a reference.
The objectref in the local variable at <n> is pushed onto the operand stack.
把本地变量表的0号取出并压入操作数栈,0号就是this