我认为java应该对反编译非常友好,也就是说,.class文件本身有很多数据仍然很好地类似于原始数据源。
是否有可能从反编译的.class文件构造原始源,这将完全等效,或者是否存在在此过程中转换的任何java构造?
例如,我可以看到语法糖就像增强循环导致问题一样。
我可以多次重复此过程并仍然可以到达我开始的地方吗?
答案 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代码。