2011-10-24 44 views
4

我想在Java中使用JAD反編譯幾個jar文件(我嘗試了JD-GUI以及更少的運氣),但是我收到了很多錯誤。一類(容易解決)似乎是一個內部類,但我也發現了這段代碼:用JAD反編譯java - 侷限性

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; 
     } 

任何想法,這個結構原本可能已經?

回答

5

在我看來像一個枚舉switch語句。看一下enum class,這個枚舉隱式擴展。它有用於切換的ordinal方法。可能有一些OrderType枚舉常量LIMIT,MARKET,STOP和TAKE。

編輯:其實,我猜一些更多的信息會很好。有一些煙霧和鏡子被用於像枚舉這樣的東西。一個枚舉常量在屏幕後面有一些序數。這個序數是一堆結構中實際使用的數字。當切換一個枚舉實例時,編譯器實際上會創建一個通過一個int值(一個衆所周知的構造,這個構造已經存在一段時間)並以序號作爲輸入進行切換。

你的兩個代碼塊會發生什麼:第一個爲枚舉序列設置一個「表」(實際上只是一個數組),如果這還沒有發生的話。有一個空檢查。如果該表爲空,則它將跳轉到標籤_L2進行啓動。否則,它會跳轉到僅返回標籤_L1。第二個代碼塊(actualy 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; 
} 
+0

有一件事讓我想知道爲什麼它創建表,並且不直接使用enum的序號(它們已經是int類型)? – kan

+0

好吧,我現在明白了,用解釋更新了我的答案。 – kan

7

我認爲這是tableswitch一個枚舉。它將任意的枚舉序數值轉換爲數字0..n,它允許改進switch語句的性能。

UPDATE 剛理解它! 問題是 - 使用枚舉的代碼可以與枚舉本身分開編譯。所以它在編譯時並不知道序數值,所以它不能構造適當的tableswitch操作。所以,這就是爲什麼它引入了懶惰的SWITCH_TABLE結構來將當前可用的序數值映射到本地tableswitch int數字。

+0

好秀!我不知道爲什麼它會引入這種間接性,但是這完全解釋了它。 –

0

當在Android上使用反射API的getDeclaredFields()方法時,如果正在內建的類型包含枚舉開關,其中的枚舉在另一個類中聲明,則其中一個返回的字段將是懶惰的SWITCH_TABLE結構,稱爲something像$SWITCH_TABLE$com$company$package$ClassName$EnumName

我在使用反射來自動將類的字段映射到ContentValues,然後保存到SQLite數據庫,並且花了半天的時間試圖弄清楚爲什麼持有列名的數組總是關閉的。