由于局部变量是在堆栈上分配的,因此局部变量的内存块是在为其分配值时分配的。
举个简单的例子
class Abc {
int i = -111;
int e;
int doSomething() {
int a = 10;
int b = a + i;
int c = b + 100;
Abc d = new Abc();
e = b + c + d.a;
return e + 1000;
}
}
和来自的字节码javap -c Abc
Compiled from "Abc.java"
class Abc {
int i;
int e;
Abc();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush -111
7: putfield #2 // Field i:I
10: return
int doSomething();
Code:
0: bipush 10
2: istore_1
3: iload_1
4: aload_0
5: getfield #2 // Field i:I
8: iadd
9: istore_2
10: iload_2
11: bipush 100
13: iadd
14: istore_3
15: new #3 // class Abc
18: dup
19: invokespecial #4 // Method "<init>":()V
22: astore 4
24: aload_0
25: iload_2
26: iload_3
27: iadd
28: aload 4
30: getfield #2 // Field i:I
33: iadd
34: putfield #5 // Field e:I
37: aload_0
38: getfield #5 // Field e:I
41: sipush 1000
44: iadd
45: ireturn
}
当调用方法时,分配堆栈中称为当前帧的内存空间
如果你仔细看,甚至int a=-111;
赋值发生在一个隐式的 init 函数中Abc()
!
int a = -111;
5: bipush -111
7: putfield #2 // Field a:I
由于没有为字段变量e
分配任何值,如果是原始变量,它将为 0,如果是 Object 引用,则为 null
如果你看doSomething()
int a = 10;
0: bipush 10
对于要使用的局部变量,在这种情况下需要将初始值推入堆栈 10 。没有这个 'push' [initialization] a 的值不能被后续语句访问(因为该值不在堆栈上)。一旦将值推送到堆栈上,其他操作(如 iadd istore 等)就会在堆栈上执行
下面的语句实际上在堆空间上创建了一个对象并调用了 init 方法。这是像'e'这样的未初始化变量获取默认值的地方
15: new #3 // class Abc
18: dup
我将进一步的字节码比较留给你;)但我希望它很清楚