5

因此,我试图对已编译的 java 程序进行轻微有效的合法更改。我正在使用 JD-GUI for Mac 对其进行反编译。在大多数情况下,反编译的代码是没有错误的,但也有一些奇怪的东西,比如未声明的变量、多个相同的变量声明以及一些不易编译的奇怪语句。反编译代码中的一些奇怪的语句实在令人费解。我在使用一个 switch 语句时遇到了问题:

    switch ($SWITCH_TABLE$PackageName$ClassName$InnerEnumName()[getPlatform().ordinal()])

其中 PackageName.ClassName 是该语句所在的类,InnerEnumName 是 ClassName 中的内部枚举。另请注意,getPlatform() 是 ClassName 中的一个方法,它返回 InnerEnumName 类型的枚举

奇怪的是,当我刚刚剥离了此类有问题的语句,对其进行编译并将其重新插入程序时,它开始工作但有一些奇怪的错误。例如,当我将 switch 语句更改为

    switch (getPlatform().ordinal())

当它应该达到第 4 种情况(再次是第 4 种情况以及值 4 的情况)时,它开始达到第 3 种情况(第 3 种情况和值 3 的情况)

4

3 回答 3

3

反编译总是不完美的。反编译器必须获取字节码并对原始源进行逆向工程,找出循环在哪里,循环控制是什么等。我永远不会期望它对于非平凡的程序是完美的。

对于 $ 名称,这些名称是在“伪造”内部类的过程中内部生成的(因为 JVM 实际上并不支持内部类)。反编译器显然在弄清楚内部类是什么并适当地命名它们以及编译器为伪造事物而创建的对象方面做得并不完美。熟悉字节码格式的人可能会很快解决问题,但是,和其他人一样,这不是微不足道的。

(在这种特殊情况下,编译器似乎出于某种原因创建了一个从内部枚举值到其他一些值的映射表,并且当您“剥离”该语句时,您丢失了该映射。)

[我要补充一点,反编译器的一个大问题是 javac 是一个移动的目标。特别是像内部类实现这样的东西正在不断地调整,所以一周工作的可能在下一周失败,下一个 +.001 版本的编译器。]

于 2011-08-03T21:47:06.827 回答
1

冒着复活一个古老问题的风险——通过去掉序数上的数组间接性,原始开关的含义被改变了。

我在这里写了这个: http ://www.benf.org/other/cfr/switch-on-enum.html

突出的一点是:

想到的第一个枚举 -> 整数函数是 .ordinal()。但是 - 这有几个问题:

我们打开的枚举类不是固定的——我们不能为 case 语句获取目标序数的副本——有人可能会更改枚举的定义!有人甚至可能会删除我们用作案例标签的字段。

所以我们需要一个查找函数,它不依赖于固定的枚举值的序数(即在运行时解析它),并且可以处理删除的枚举字段。

因此,您剥离的数组 - 它是 enum 语句中的序数与 switch 语句中的位置之间的运行时映射。

这里真正有趣的是,这意味着 Javac 会为每个 switch-on-enum 创建一个额外的内部类 - 有趣!

于 2013-09-27T11:43:07.253 回答
1

JD-GUI (JD?) 似乎有问题。尝试找到更好的反编译器?太糟糕了 jad 的古老 - 它曾经很好。

于 2011-08-03T21:33:32.553 回答