我正在尝试使用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;
}
知道这个结构最初可能是什么?
答案 0 :(得分:7)
我认为枚举是tableswitch。它将任意枚举序数值转换为数字0..n,它可以提高switch语句的性能。
<强>更新强> 刚才明白了! 问题是 - 使用枚举的代码可以与枚举本身分开编译。所以它在编译时不知道序数值,所以它不能构造一个合适的tableswitch op。所以,这就是为什么它引入了懒惰的SWITCH_TABLE结构来将当前可用的序数值映射到本地tableswitch int数字。
答案 1 :(得分:5)
在我看来就像枚举上的switch语句。看一下enum class,其中隐含地扩展了枚举。它具有用于切换的ordinal
方法。可能有一些OrderType
枚举,常量为LIMIT,MARKET,STOP和TAKE。
在你的两个代码块中会发生这样的事情:第一个为枚举数设置一个“表”(实际上只是一个数组),如果这还没有发生的话。有一个空检查。如果表为null,它将跳转到标签_L2
以进行启动。否则,它会跳转到仅返回的标签_L1
。第二个代码块(实际的switch语句)对int进行了切换。通过获取与枚举常量的序数对应的索引处的元素,从表中获取int。
这似乎有点奇怪,但这会在枚举和交换机内部使用的值之间形成某种间接。
现在,这一切看起来如此低级而不是简单地看到enum上的开关的原因是在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;
}
答案 2 :(得分:0)
在Android上使用反射API的getDeclaredFields()方法时,如果被内省的类型包含枚举开关,其中枚举是在另一个类中声明的,则其中一个返回的字段将是惰性SWITCH_TABLE结构,称为类似$SWITCH_TABLE$com$company$package$ClassName$EnumName
。
我使用反射在保存到SQLite数据库之前自动将类的字段映射到ContentValues
,并且只花了半天时间试图弄清楚为什么持有列名的数组总是关闭的之一。