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

为什么不同的Java de编译器显示不同的源代码?,java,compiler-construction,decompiling,decompiler,Java,Compiler Construction,Decompiling,Decompiler,我试图通过反编译.class文件来理解Java编译器是如何工作的。我使用了Java反编译器()和showmycode() 它们在.java文件中显示不同的源代码。 为什么?我应该相信哪一个 .java文件 class HelloWorld{ public static void main(String[] args){ System.out.println("Hello, World!"); } } import java.io.PrintStream; cla

我试图通过反编译.class文件来理解Java编译器是如何工作的。我使用了Java反编译器()和showmycode() 它们在.java文件中显示不同的源代码。 为什么?我应该相信哪一个

.java文件

class HelloWorld{
    public static void main(String[] args){
        System.out.println("Hello, World!");
    }
}
import java.io.PrintStream;
class HelloWorld {
   HelloWorld() {
   } 
   public static void main(string args[]) 
   {
       system.out.println("Hello, World!"); 
   }
}
.java反编译器反编译的类文件:

import java.io.PrintStream;

class HelloWorld
{
  public static void main(String[] paramArrayOfString)
  {
    System.out.println("Hello, World!");
  }
}
由showmycode反编译的.class文件

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

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

(假设showmycode将解决其案例问题,请参见下文)三个源代码—原始代码、java反编译器创建的代码和showmycode创建的代码是幂等的。它们以不同的方式书写,但做的事情完全相同。两个反编译器都是正确的

这里解释了不同之处:

  • 构造函数存在/不存在:每个类都有一个构造函数。如果程序员不提供构造函数,编译器将生成一个。智能反编译程序将识别出这一点,并假设为空的构造函数生成了它,从而从反编译的源代码中省略它
  • 数组的
    []
    位置:声明
    String[]foo
    String foo[]
    是相同的。我建议总是选择
    String[]foo
    ,因为在Java(与C相反)中,数组是该类型的属性,而不是变量
  • 格式化/放置
    {}
    ,缩进等:基本上根本不重要。这可能对调试信息(堆栈跟踪的行号)有一点影响,但这不是代码重要行为的一部分,这正是我们感兴趣的
  • 自动变量(包括参数变量在内的局部变量)的名称在二进制文件中不可用,因此反编译程序在反编译时必须发明新名称
请注意,showmycode似乎存在类型名称大小写的问题。Java区分大小写,必须是
System
String
,而不是
System
String
。showmycode似乎出错了,这意味着除非手动修复所有这些类型名,否则代码无法再次编译


showmycode的另一个问题是如何处理varargs方法。我将main的签名更改为
publicstaticvoidmain(String…args)
以查看我得到了什么,我得到了
publicstatictransientedvoidmain(stringargs[])
,它没有编译。如今,反编译器被期望生成正确的、可编译的源代码,而showmycode则不然。

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

反编译器生成的代码尝试与原始代码执行相同的操作,但不会重新生成完全相同的原始代码。如果我只知道三个数字加起来等于10,那么如果我使用[2,4,4]、[1,2,7]或[3,4,3]来达到这一点,差别不大;它们都产生与原始公式执行时相同的输出。如果您想了解编译器是如何工作的,请使用反汇编程序查看实际生成的字节码。理想情况下,不要使用
javap
,因为它隐藏了东西。它说的是字符串而不是字符串,系统而不是系统。在这种情况下,Java是区分大小写的。这是低质量的答案。@dandavis已经在评论中给出了相同的解释before@xmojmr非顺序逻辑。事实上,其他人在他们的评论和回答中提供了相同的信息,这并不意味着这篇文章的质量低下。在我看来,用拉丁语辩论并不能使你的答案更好。你的回答对已经说过的话没有什么新的补充。没有任何证据、证据或与支持事实相关联的索赔。使用“烹饪”隐喻和误导性术语()也没有帮助。模糊的单行回答可能有助于声誉搜寻,但它们通常属于评论部分question@xmojmr有一次你没抓住要点。在我看来,这个答案不需要改进。如果你认为低质量的答案包括正确的答案,我建议需要修改。隐喻的使用不会使答案无效,其他人在大致相同的时间陈述了相同的事情也不会使答案无效。数千年来,拉丁语一直被用作最短的方式来表达你的推论是无效的。你已经错过了我的观点(如果我忽略了没有几种方法可以编写以单个文本作为参数的单个函数调用,并且你没有回答OP问题中的“我应该相信哪个”部分)。虽然你的观点和观察可能是正确的,我们只是在工程方面,但用“相信我”的原则构建问答知识库是没有用的。你可以做得更好。。我是说在你建议的修改之后。这是一个集合体。短人命