【问题标题】:Decompiling java with JAD - limitations使用 JAD 反编译 java - 限制
【发布时间】:2011-10-24 09:43:09
【问题描述】:

我正在尝试使用 Java 中的 JAD 反编译几个 jar 文件(我也尝试过 JD-GUI,但运气更差),但出现了很多错误。一种类型(易于修复)似乎是内部类,但我也发现了这段代码:

static int[] $SWITCH_TABLE$atp$com$OrderType()
{
    $SWITCH_TABLE$atp$com$OrderType;
    if($SWITCH_TABLE$atp$com$OrderType == null) goto _L2; else goto _L1
_L1:
    return;
_L2:
    JVM INSTR pop ;
    int ai[] = new int[OrderType.values().length];
    try
    {
        ai[OrderType.LIMIT.ordinal()] = 2;
    }
    catch(NoSuchFieldError _ex) { }
    try
    {
        ai[OrderType.MARKET.ordinal()] = 1;
    }
    catch(NoSuchFieldError _ex) { }
    try
    {
        ai[OrderType.STOP.ordinal()] = 3;
    }
    catch(NoSuchFieldError _ex) { }
    try
    {
        ai[OrderType.TAKE.ordinal()] = 4;
    }
    catch(NoSuchFieldError _ex) { }
    return $SWITCH_TABLE$atp$com$OrderType = ai;
}

具体用法如下:

switch($SWITCH_TABLE$atp$com$OrderType()[co.getOrderType().ordinal()])
        {
        case 1: // '\001'
            order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
            break;

        case 2: // '\002'
            order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderPrice(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
            break;

        case 3: // '\003'
            order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderPrice(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
            break;
        }

知道这个结构最初可能是什么吗?

【问题讨论】:

    标签: java decompiling jad


    【解决方案1】:

    我认为它是 tableswitch 用于枚举。它将任意枚举序数值转换为数字 0..n,它可以提高 switch 语句的性能。

    更新 才明白! 问题是 - 使用枚举的代码可以与枚举本身分开编译。所以它在编译时不知道序数值,所以它不能构造一个合适的 tableswitch 操作。所以,这就是它引入惰性 SWITCH_TABLE 结构来将当前可用的序数值映射到本地 tableswitch int 数字的原因。

    【讨论】:

    • 好节目!我不知道它为什么会引入这种间接性,但这完美地解释了它。
    【解决方案2】:

    在我看来就像一个枚举上的 switch 语句。看看enum class,枚举隐式扩展。它具有用于切换的ordinal 方法。可能有一些带有常量 LIMIT、MARKET、STOP 和 TAKE 的 OrderType 枚举。

    编辑:实际上,我猜更多信息会很好。有一些烟雾和镜子被用于枚举之类的东西。枚举常量在屏幕后面得到一些序数。这个序数是一堆结构中实际使用的。在切换枚举实例时,编译器实际上会创建一个以序数作为输入的 int(一种已经存在了一段时间的众所周知的构造)的切换。

    在您的两个代码块中发生的情况是:第一个为枚举序数设置一个“表”(实际上只是一个数组),如果这还没有发生的话。有一个空检查。如果表为空,它将跳转到标签_L2 进行启动。否则,它会跳转到标签_L1,它只是返回。第二个代码块(实际的 switch 语句)在 int 上进行 switch。通过获取与枚举常量的序号对应的索引处的元素,从表中获取 int。

    这似乎有点奇怪,但这在枚举序数和开关内部使用的值之间形成了某种间接性。

    现在,这一切看起来如此低级而不是简单地看到枚举上的开关的原因是枚举是在 JDK 1.5 中引入的,但是 JAD 已经停止维护一段时间了,只真正支持反编译源代码到 1.4。看到枚举是如何使用 1.4 中可用的构造实现的,反编译确实有效,但 JAD 不了解枚举,因此没有努力以更清晰的方式呈现这一点。

    第二个代码块可能如下所示:

    switch(co.getOrderType()) { //co.getOrderType() gets the OrderType of some variable
        case MARKET : order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
                      break;
        case LIMIT : order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderPrice(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
                     break;
        case STOP : order = new Order(userID, null, co.getOrderType(), co.getOrderSide(), co.getOrderPrice(), co.getOrderID(), co.getOrderSecurity(), co.getOrderQuantity(), broker);
                    break;
    }
    

    【讨论】:

    • 有一件事让我感到奇怪,为什么它会创建表,只是不直接使用枚举的序数(它们已经是ints)?
    【解决方案3】:

    在 Android 上使用反射 API 的 getDeclaredFields() 方法时,如果被自省的类型包含一个枚举开关,其中该枚举在另一个类中声明,则返回的字段之一将是惰性 SWITCH_TABLE 结构,称为类似$SWITCH_TABLE$com$company$package$ClassName$EnumName.

    在保存到 SQLite 数据库之前,我使用反射将类的字段自动映射到 ContentValues,并且只花了半天时间试图弄清楚为什么保存列名的数组总是关闭一个。

    【讨论】:

      猜你喜欢
      • 2011-01-03
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 2011-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多