编译成.class并反编译时是否丢失了任何信息?

时间:2015-05-15 14:53:59

标签: java decompiling

我认为java应该对反编译非常友好,也就是说,.class文件本身有很多数据仍然很好地类似于原始数据源。

是否有可能从反编译的.class文件构造原始源,这将完全等效,或者是否存在在此过程中转换的任何java构造?

例如,我可以看到语法糖就像增强循环导致问题一样。

我可以多次重复此过程并仍然可以到达我开始的地方吗?

3 个答案:

答案 0 :(得分:3)

有几个反编译器可以做到这一点,它通常取决于代码的复杂性。根据我的经验,泛型有时会破坏反编译,但常规POJO可以返回确切的类。

答案 1 :(得分:3)

简单的答案是,信息丢失了。

特别是评论总是丢失。原始变量名是否丢失取决于编译代码时的编译器选项。使用调试选项(-g)编译的代码在反编译时更具可读性。

反编译时,您获得功能相同的源代码,但与源时的源代码不完全相同。

答案 2 :(得分:1)

考虑以下两种方法:

public class MyTest {
    public String hi(String name) {
        return "Hi " + name;
    }

    public String howdy(String name) {
        return new StringBuilder().append("Hi ").append(name).toString();
    }
}

以下是反编译代码:

$ javap -c MyTest.class 
Compiled from "MyTest.java"
public class MyTest {
  public MyTest();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public java.lang.String hi(java.lang.String);
    Code:
       0: new           #2                  // class java/lang/StringBuilder
       3: dup           
       4: invokespecial #3                  // Method java/lang/StringBuilder."<init>":()V
       7: ldc           #4                  // String Hi 
       9: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      12: aload_1       
      13: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      16: invokevirtual #6                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      19: areturn       

  public java.lang.String howdy(java.lang.String);
    Code:
       0: new           #2                  // class java/lang/StringBuilder
       3: dup           
       4: invokespecial #3                  // Method java/lang/StringBuilder."<init>":()V
       7: ldc           #4                  // String Hi 
       9: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      12: aload_1       
      13: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      16: invokevirtual #6                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      19: areturn       
}

这只是语言中视觉上不同构造的一个简单示例,它们被编译为完全相同的字节码。因此,严格来说,您无法生成完全相同的代码。除非编译器添加了调试信息,否则反编译器将不会看到本地变量名称。

还有像ProGuard这样的字节码混淆工具,声称无法自动反编译。

但是,如果反编译器成功生成java代码,那么编译和反编译它(使用相同的编译器和反编译器)应该生成相同的java代码。