我写了一个简单的代码:
L11 public void sum2() {
L12 int a = 25;
L13 try {
L14 int b = 8;
L15 if (a > 20) {
L16 int k = a + b;
L17 System.out.println("k=" + k);
L18 }
L19 } catch (Exception e) {
L20 e.printStackTrace();
L21 }
L22 }
我认为变量a的作用域一定是在try语句中,即第15~18行。
但实际上,当我使用 javap 生成字节码时:
Exception table:
from to target type
3 41 44 Class java/lang/Exception
LineNumberTable:
line 12: 0
line 14: 3
line 15: 6
line 16: 12
line 17: 16
line 21: 41
line 19: 44
line 20: 45
line 22: 49
LocalVariableTable:
Start Length Slot Name Signature
16 25 3 k I
6 35 2 b I
45 4 2 e Ljava/lang/Exception;
0 50 0 this Lcom/buzz/asm/util/Sum;
3 47 1 a I
StackMapTable: number_of_entries = 3
frame_type = 252 /* append */
offset_delta = 41
locals = [ int ]
frame_type = 66 /* same_locals_1_stack_item */
stack = [ class java/lang/Exception ]
frame_type = 4 /* same */
变量b的范围是第15~21行? (开始=6,结束=41),为什么?
为什么JVM ByteCode的LocalVariableTable不正确?
这是您的方法的 LocalVariableTable 的细分:
this
是对当前对象的引用,它始终位于槽 0 中并且在整个方法的范围内。
a
位于插槽 1 中,范围从字节码指令 3 到指令 50(整个方法)。
b
位于槽 2 中,范围从指令 6 到指令 41(try 块和以下代码)。
k
位于槽 3 中,范围从指令 16 到指令 41(在 try 块的 if 语句内)。
e
位于槽 2 中,范围为指令 45 到指令 49(catch 块)。
Java 中变量的作用域由声明它的位置决定。在您的代码中,变量
b
是在 try
块内声明的,因此其范围仅限于该块以及嵌套在其中的任何块。
Start
中的Length
和LocalVariableTable
值表示变量所在范围内的字节码指令范围。 Start
值是变量在作用域内的第一个字节码指令的索引,Length
是变量保留在作用域内的字节码指令的数量。
在您的情况下,
b
位于插槽2
中,并且在从字节码指令6
到指令41
的范围内。此范围包括整个 try
块和以下代码,直到 catch
块的开头。这是因为 catch
块是一个单独的范围,并且 b
不在该范围内。
因此,
b
的范围不仅仅是源代码中的第 15-18 行,而是从其声明延伸到 try
块的末尾,并包含直到 catch
开头的任何其他代码
块。这与 Java 的作用域规则一致,其中变量的作用域是从声明它的点到声明它的块的末尾。