正如其他人已经指出的那样:反编译器(通常)无法区分导致相同字节码的不同源代码。
遗憾的是,您没有提供该方法的完整代码。因此,以下内容包含一些关于此循环在方法中出现的位置和方式的猜测(这些猜测可能会在某种程度上扭曲结果)。
但是,让我们在这里看一些往返。请考虑以下类,其中包含具有您发布的代码的两个版本的方法:
import java.io.BufferedReader;
import java.io.IOException;
import java.util.regex.Pattern;
public class DecompileExample {
public static void methodA(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
String[] colArr = line.split(Pattern.quote("|"));
} else {
i++;
}
}
}
public static void methodB(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
for (String[] colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}
}
}
编译它
javac DecompileExample.java -g:none
将创建相应的类文件。(注意:该参数将导致编译器省略所有调试信息。否则,反编译器可能会使用调试信息来重建原始代码的更逐字版本,特别是包括原始变量名称)-g:none
现在查看这两种方法的字节代码,使用
javap -c DecompileExample.class
将产生以下内容:
public static void methodA(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aload_0
5: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
8: dup
9: astore_1
10: ifnull 61
13: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
16: new #4 // class java/lang/StringBuilder
19: dup
20: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
23: ldc #6 // String line:
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: aload_1
29: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
38: iload_2
39: ifne 55
42: aload_1
43: ldc #10 // String |
45: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
48: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
51: astore_3
52: goto 4
55: iinc 2, 1
58: goto 4
61: return
和
public static void methodB(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aconst_null
5: astore_3
6: aload_0
7: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
10: dup
11: astore_1
12: ifnull 60
15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
18: new #4 // class java/lang/StringBuilder
21: dup
22: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
25: ldc #6 // String line:
27: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_1
31: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: iload_2
41: ifne 54
44: aload_1
45: ldc #10 // String |
47: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
50: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
53: astore_3
54: iinc 2, 1
57: goto 6
60: return
}
(有一个很小的区别:被翻译成String[] colArr = null
aconst null
astore_3
在第二个版本的开头。但这是与您在问题中省略的部分代码相关的方面之一)。
您没有提到您正在使用哪一个,但是来自 http://jd.benow.ca/ 的JD-GUI反编译器将其反编译为以下内容:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.regex.Pattern;
public class DecompileExample
{
public static void methodA(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
String[] arrayOfString = str.split(Pattern.quote("|"));
} else {
i++;
}
}
}
public static void methodB(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
String[] arrayOfString = null;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
arrayOfString = str.split(Pattern.quote("|"));
}
i++;
}
}
}
您可以看到,这两种情况下的代码是相同的(至少关于循环 - 还有一个关于“虚拟变量”的差异,我必须引入它才能编译它,但这与问题无关,可以这么说)。
tl;dr 消息很清楚:
不同的源代码可以编译成相同的字节码。因此,可以将相同的字节代码反编译为不同的源代码。但是每个反编译器都必须满足于一个版本的源代码。
(附注:我有点惊讶地发现,在没有编译时(即,当保留调试信息时),JD-GUI甚至以某种方式设法重建第一个使用-循环,第二个使用-循环。但一般来说,当省略调试信息时,这根本不可能)。-g:none
while
for