invokeinterface:調用一個接口方法在這段Java匯編代碼中,addUser()方法是在第四行的“5:invokevitual#23″進行調用的。這表示對應索引為23的方法會被調用。索引為23的方法的名稱已經被javap給注解在旁邊了。invokevirtual是Java字節碼里調用方法的最基本的操作碼。在Java字節碼里,有四種操作碼可以用來調用一個方法,分別是:invokeinterface,invokespecial,invokestatic以及invokevirtual。操作碼的作用分別如下:
invokespecial: 調用一個初始化方法,私有方法或者父類的方法
invokestatic:調用靜態方法
invokevirtual:調用實例方法
Java字節碼的指令集由操作碼和操作數組成。類似invokevirtual這樣的操作數需要2個字節的操作數。
用更新的類庫來編譯上面的應用代碼,然后反編譯它,將會得到下面的結果。
1
2
3
4
5
6
7
8
|
public void add(java.lang.String); Code: 0 : aload_0 1 : getfield # 15 ; //Field admin:Lcom/nhn/user/UserAdmin; 4 : aload_1 5 : invokevirtual # 23 ; //Method com/nhn/user/UserAdmin.addUser:(Ljava/lang/String;)Lcom/nhn/user/User; 8 : pop 9 : return |
你會發現,對應索引為23的方法被替換成了一個返回值為”Lcom/nhn/user/User”的方法。
在上面的反匯編代碼里,代碼前面的數字代碼什么呢?
它表示的是字節數。大概這就是為什么運行在JVM上面的代碼成為Java“字節”碼的原因。簡而言之,Java字節碼指令的操作碼,例如aload_0,getfield和invokevirtual等,都是用一個字節的數字來表示的(aload_0=0x2a,getfield=0xb4,invokevirtual=0xb6)。由此可知Java字節碼指令的操作碼最多有256個。
aload_0和aload_1這樣的指令不需要任何操作數。因此,aload_0指令的下一個字節是下一個指令的操作碼。不過,getfield和invokevirtual指令需要2字節的操作數。因此,getfiled的下一條指令是跳過兩個字節,寫在第四個字節的位置上的。十六進制編譯器里查看字節碼的結果如下所示。
1
|
2a b4 00 0f 2b b6 00 17 57 b1 |
表一:Java字節碼中的類型表達式在Java字節碼里,類的實例用字母“L;”表示,void 用字母“V”表示。通過這種方式,其他的類型也有對應的表達式。下面的表格對此作了總結。
Java Bytecode | Type | Description |
B | byte | signed byte |
C | char | Unicode character |
D | double | double-precision floating-point value |
F | float | single-precision floating-point value |
I | int | integer |
J | long | long integer |
L<classname> | reference | an instance of class <classname> |
S | short | signed short |
Z | boolean | true or false |
[ | reference | one array dimension |
原文轉自:http://www.anti-gravitydesign.com