为什么不同的Java反编译器显示不同的源代码?

问题描述 投票:0回答:2

我试图通过反编译 .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!"); 
   }
}
java decompiling decompiler
2个回答
8
投票

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

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

以下是差异解释:

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

似乎存在类型名称大小写问题。 Java 区分大小写,必须是 System

String
,而不是
system
string
。似乎
showmycode
出现了这个错误,这意味着除非您手动修复所有这些类型名称,否则无法再次编译代码。 showmycode

的另一个问题是它如何处理可变参数方法。我将 main 的签名更改为

public static void main(String... args) 来看看我得到了什么,我得到了 public static transient void main(string args[])

,但无法编译。如今,反编译器应该生成正确的、可编译的源代码,而 
showmycode
 却不能。

因为大多数语句都有多种不同的编写方式,所以它们都归结为相同的目标代码。一般来说,没有单一正确的反编译。

0
投票

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.