是否有任何Java反编译器可以正确地反编译对重载方法的调用?

是否有任何Java反编译器可以正确地反编译对重载方法的调用?,java,decompiler,jad,Java,Decompiler,Jad,考虑这个(非常简单的)例子: 公共类反编译测试{ 公共静态void main(字符串[]args){ 对象s1=“答案”,s2=“答案”; doPrint((Object)“您应该知道:”; 对于(int i=0;i

考虑这个(非常简单的)例子:

公共类反编译测试{
公共静态void main(字符串[]args){
对象s1=“答案”,s2=“答案”;
doPrint((Object)“您应该知道:”;
对于(int i=0;i<2;i++){
doPrint(s1);
doPrint(s2);
s1=“是”;
s2=新的整数(42);
}
System.out.println();
}
私有静态void doPrint(字符串s1){
系统输出打印(“错误!”);
}
私有静态void doPrint(对象s1){
系统输出打印(s1+“”);
}
}
使用源/目标级别1.1编译它,而不使用调试信息(即不应存在任何局部变量信息),并尝试对其进行反编译。我试过Jad、JD-GUI和Fernflower,它们都至少有一个调用错误(即程序至少打印了一次“错误”)

是否真的没有java反编译器可以推断正确的强制转换,从而不会调用错误的重载

编辑:目标级别1.1,这样就不会出现特定于Java6的快速验证信息。这可能会给反编译器一个线索,表明s1已声明为
对象
,而不是
字符串
。反编译器应该能够在没有这些信息的情况下反编译代码(不一定获得原始变量类型,但显示相同的行为),特别是因为许多模糊器也会将其剥离

哪些反编译器出错:

  • 在第一次调用中,他们错过了对
    (对象)
    的转换
  • 他们推断出
    s1
    的类型为
    String
    ,但忘记在调用
    doPrint
    时添加强制转换(因此调用字符串版本而不是对象版本)
  • 一个蹩脚的(我甚至没有列出)甚至将
    s2
    的类型推断为字符串,导致代码不可编译

在任何情况下,此代码都不会调用
字符串
重载,但反编译的代码会调用。

用于反编译的JadClipse Eclipse插件还提供了JODE反编译器,您可能需要尝试一下。我在Jad放弃的时候用它

此外,Dava反编译器还使用了烟尘,我上次查看时,烟尘在重建原始Java代码方面非常雄心勃勃。我没有试过你的例子,但你可能想看看

你好,米希

很抱歉反应太晚。我在抄袭我的答案

你的问题其实是众所周知的。让我们看看:


1) 纯字节码不包含任何关于对象变量类型的信息,因此在第一次传递中,s1和s2被声明为对象

2) 反编译器正在努力为每个变量分配最好的类型((“最窄类型原则”在Fernflower中实现)。所以s1和s2被正确地标识为字符串的实例

3) 调用doPrint可以直接链接到正确的方法
私有静态void doPrint(对象s1)

4) 到目前为止一切都还好吧?现在我们已经将一个字符串变量s1传递给一个函数,该函数需要一个对象。我们需要投吗?您可能会认为,并不是这样,因为Object是字符串的超级类型。但我们确实这样做了,因为在同一个类中有另一个函数具有相同的名称和不同的参数签名。因此,我们需要对整个班级进行分析,以确定是否需要演员阵容

5) 一般来说,这意味着我们需要分析所有库中的所有引用类,包括java运行时。工作量很大!事实上,这一特性是在Fernflower的一些alpha版本中实现的,但由于性能和内存损失,还没有在产品中实现。其他提到的反编译器在设计上缺乏这种能力

希望我已经澄清了一点:)

正确地处理所有重载方法,甚至是在基元类型上重载的方法,大多数反编译器都会出错。它总是将参数强制转换为被调用方法的确切类型,因此代码可能比需要的更混乱,但至少它是正确的


披露:我是Krakatau的作者。

应该正确处理重载方法调用。与Krakatau一样,Procyon最初会为与目标方法不完全匹配的每个方法参数插入强制转换。但是,其中大部分将在反编译的后期阶段删除,该阶段将识别并消除冗余强制转换。Procyon只有在能够验证这样做不会导致调用绑定到其他方法时,才会删除调用参数的强制转换。例如,如果声明该方法的
.class
无法解析,它将根本不会尝试删除强制转换,因为它无法知道哪些重载可能会冲突。

添加到前面的答案中: 以下是截至2015年3月的现代反编译器列表:

  • 前体
  • CFR
  • 法学博士
  • 蕨类植物
它们都支持重载方法。

您可以在线测试上述反编译器,无需安装,并自行选择。
云中的Java反编译器:

你说“他们打错电话了”是什么意思?反编译后他们生成了什么源?Dava和其他人一样失败了。Jode工作了,但由于Jode几乎会在所有通过任何模糊处理程序的程序上崩溃,这对我没有什么帮助:(我猜我问错了问题。)投反对票并接受答案?这是新的:)改变了我被接受的答案,如果你不喜欢被否决和接受:)(我首先否决了你,因为你的建议也不起作用,但后来决定从所有被否决的答案中,你是最好的)-顺便问一下,你从哪里可以看出是我被否决和接受了?是的,我知道一般问题(这就是为什么我不难将一个更长的类缩减为上面的示例)
public class DecompilerTest {
    public static void main(String[] args) {
        Object s1 = "The", s2 = "answer";
        doPrint((Object) "You should know:");
        for (int i = 0; i < 2; i++) {
            doPrint(s1);
            doPrint(s2);
            s1 = "is";
            s2 = new Integer(42);
        }
        System.out.println();
    }

    private static void doPrint(String s1) {
        System.out.print("Wrong!");
    }

    private static void doPrint(Object s1) {
        System.out.print(s1 + " ");
    }
}