【问题标题】:Why different Java de-compilers show different source code?为什么不同的 Java 反编译器显示不同的源代码?
【发布时间】:2015-02-20 05:41:12
【问题描述】:

我试图通过反编译 .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!");
  }
}

由showmycode反编译的.class文件

import java.io.PrintStream;
class HelloWorld {
   HelloWorld() {
   } 
   public static void main(string args[]) 
   {
       system.out.println("Hello, World!"); 
   }
}

【问题讨论】:

  • 反编译器生成的代码试图与原始代码做相同的事情,它不会重新生成确切的原始代码。如果我只能说三个数字加起来等于 10,那么我使用 [2,4,4]、[1,2,7] 或 [3,4,3] 来到达那里没有什么区别;它们都产生与执行原始公式时相同的输出。
  • 如果您想了解编译器的工作原理,请使用反汇编程序查看生成的实际字节码。理想情况下,不要使用javap,因为它会隐藏东西。

标签: java compiler-construction decompiling decompiler


【解决方案1】:

反编译器不能重新创建原始源代码,它只能创建一个新的源代码,它将编译成与原始源代码相同的二进制文件。

(假设 showmycode 将修复他们的案例问题,见下文)三个源代码 - 原始的,由 java decompiler 创建的和由showmycode幂等的。它们以不同的方式编写,但做完全相同的事情。两个反编译器都是对的。

以下是不同之处的解释:

  • 存在/不存在构造函数:每个类都有一个构造函数。如果程序员不提供构造函数,编译器将生成一个。智能反编译器会识别这一点,并假设它是生成的 empty 构造函数,因此从反编译的源代码中将其省略。
  • 数组[] 的位置:String[] fooString foo[] 的声明是相同的。我建议总是选择String[] foo,因为在 Java(与 C 相对)中,数组是类型的属性,而不是变量。
  • {} 的格式/位置、缩进等:大部分都无关紧要。调试信息(堆栈跟踪的行号)可能有点重要,但这不是代码的重要行为的一部分,这是我们感兴趣的。
  • 自动变量(包括参数变量的局部变量)的名称在二进制文件中不可用,因此反编译器必须在反编译时发明新名称。

请注意,showmycode 似乎存在类型名称大小写的问题。 Java 区分大小写,必须是SystemString,而不是systemstring。似乎 showmycode 弄错了,这意味着除非您手动修复所有这些类型名称,否则无法再次编译代码。

showmycode 的另一个问题是它如何处理可变参数方法。我将 main 的签名更改为public static void main(String... args) 以查看我得到了什么,我得到了public static transient void main(string args[]),它无法编译。如今,反编译器被期望生成正确的、可编译的源代码,而 showmycode 却没有。

【讨论】:

  • 实际上我已经完全按照它显示的方式粘贴了 showmycode 代码。它确实说字符串而不是字符串和系统而不是系统。
  • 在这种情况下,废弃 showmycode,Java 区分大小写。
【解决方案2】:

因为有几种不同的方法可以编写大多数语句,所有这些都归结为相同的目标代码。通常没有单一正确的反编译。

【讨论】:

  • 这是低质量的答案。 @dandavis 之前已经提供了相同的解释作为评论
  • @xmojmr Non sequitur. 其他人在他们的 cmets 和答案中提供了相同的信息这一事实并不表明此问题的质量低下。相反,它表示同意答案是什么。
  • 在我看来,用拉丁语争论并不能让你的答案更好。您的回答对已经说过的内容没有任何新意。在没有任何证据、证据或支持事实的链接的情况下提出索赔。使用“烹饪”隐喻和误导性术语 ("object code") 也无济于事。模糊的单行答案可能有利于声誉搜索,但它们通常属于问题的评论部分
  • @xmojmr 再次,您错过了重点。在我看来,这个答案不需要变得更好。如果您对低质量答案的想法包括正确答案,我建议它需要修改。隐喻的使用不会使答案无效,而且其他人在大致相同的时间说了同样的话也不会使答案无效。几千年来,拉丁语一直被用作传达您的推论无效的最短途径。
  • 你错过了我的观点(如果我忽略了没有几种方法可以使用单个文字作为参数编写单个函数调用,并且你没有回答“我应该信任哪个”部分OP的问题)。尽管您的意见和观察可能是正确的,我们don't care about science 但仅与工程有关,但根据“相信我”公理组成问答知识库是没有用的。你可以做得更好。我是说在你建议的修改之后。 De omnibus est dubitandum人类的短暂生命
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多