java反编译foreach循环
反编译。下面的类文件为每个循环生成有趣的结果
源-主。爪哇:
public class Main {
public static void main(String[] args) {
String[] names = new String[3];
int var3 = 3;
for (String name : names) {
System.out.println(name);
}
}
}
Result-Main。课程:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class Main {
public Main() {
}
public static void main(String[] args) {
String[] names = new String[3];
int var3 = true;
String[] var3 = names;
int var4 = names.length;
for(int var5 = 0; var5 < var4; ++var5) {
String name = var3[var5];
System.out.println(name);
}
}
}
这个文件是用IntelliJ IDEA反编译的
- 为什么将
true
分配给未使用的int
李> - 为什么重新声明
var3
变量李>
这代表反编译程序是个错误吗
# 1 楼答案
在字节码级别,没有局部变量的正式声明,至少没有源代码中已知的方式。一个方法声明了同时存在的局部变量的最大数量或为它们保留的“时隙”。当一个局部变量被分配了一个实际值(通过“slot”索引)并且至少存在于该值的最后一次读取时,该局部变量就开始生效
通过这些操作,无法识别变量的作用域何时结束,或者两个作用域不相交的变量是否共享一个时隙(与对同一变量的多个赋值相比)。如果它们有完全不兼容的类型,它们的赋值会给出提示
为了帮助调试,有一个可选的代码属性提供有关声明的局部变量及其作用域的提示,但这并不要求完整,也不会影响JVM执行字节码的方式。但在这里,该属性似乎已经存在,并已被反编译器使用
当我用
javac -g
编译示例代码时,我得到声明的变量
args
(方法参数)、names
、var3
和name
按顺序分配给变量索引0
、1
、2
和6
有些合成变量没有声明
3
处保存循环正在迭代的数组的引用4
处保存数组长度5
处保存int
索引变量,该变量将在循环中递增反编译器似乎有一个简单的策略来处理
LocalVariableTable
中不包含的变量。它生成一个由前缀"var"
和堆栈框架内的索引组成的名称。因此,它为上述合成变量生成了名称var3
、var4
和var5
,并且不关心这些生成的名称与显式声明的名称之间是否存在名称冲突,即var3
现在,不清楚为什么反编译器会为
int
变量生成true
赋值,但它有助于了解Java字节码中没有专用的boolean
处理指令,而是以与int
值相同的方式处理boolean
值。它需要适当的元信息,比如变量声明,来理解值何时应该被解释为boolean
值。也许,上面提到的名称冲突导致反编译器混淆了以后的变量类型,最终考虑值类型不是^ {< CD13> },然后回落到将它当作^ {CD22}}。但这只是猜测;可能还有一个完全无关的bug