我试图通过反编译 .class 文件来了解 Java 编译器的工作原理。我使用了Java反编译器(http://jd.benow.ca/)和showmycode(http://www.showmycode.com/) 他们向我展示了 .java 文件中的不同源代码。 为什么?我应该相信哪个。
.java 文件
class HelloWorld{
public static void main(String[] args){
System.out.println("Hello, World!");
}
}
java反编译器反编译后的.class文件:
import java.io.PrintStream;
class HelloWorld
{
public static void main(String[] paramArrayOfString)
{
System.out.println("Hello, World!");
}
}
.class 文件由 showmycode 反编译
import java.io.PrintStream;
class HelloWorld {
HelloWorld() {
}
public static void main(string args[])
{
system.out.println("Hello, World!");
}
}
反编译器无法重新创建原始源代码,它只能创建一个新的源代码,该新源代码将编译成与原始源代码相同的二进制文件。
(假设 showmycode 会解决他们的案例问题,见下文)这三个源代码 - 原始代码、由 java decompiler 创建的代码和由 showmycode 创建的代码是 idempot 的。它们以不同的方式编写,但做完全相同的事情。两个反编译器都是对的。
以下是差异解释:
[]
String[] foo
和String foo[]
是相同的。我建议始终选择 String[] foo
,因为在 Java(与 C 相对)中,数组是类型的属性,而不是变量。{}
重要行为的一部分,而这正是我们感兴趣的。 自动变量(局部变量,包括参数变量)的名称在二进制文件中不可用,因此反编译器在反编译时必须发明新名称。
似乎存在类型名称大小写问题。 Java 区分大小写,必须是 System
和
String
,而不是 system
和 string
。似乎 showmycode出现了这个错误,这意味着除非您手动修复所有这些类型名称,否则无法再次编译代码。 showmycode的另一个问题是它如何处理可变参数方法。我将 main 的签名更改为
public static void main(String... args)
来看看我得到了什么,我得到了 public static transient void main(string args[])
,但无法编译。如今,反编译器应该生成正确的、可编译的源代码,而showmycode
却不能。因为大多数语句都有多种不同的编写方式,所以它们都归结为相同的目标代码。一般来说,没有单一正确的反编译。