在一般的Java應用開發過程中,開發人員使用Java的方式比較簡單。打開慣用的IDE,編寫Java源代碼,再利用IDE提供的功能直接運行Java 程序就可以了。這種開發模式背後的過程是:開發人員編寫的是Java源代碼文件(.java),IDE會負責調用Java的編譯器把Java源代碼編譯成平臺無關的字節代碼(byte code),以類文件的形式保存在磁盤上(.class)。Java虛擬機(JVM)會負責把Java字節代碼加載並執行。
從Java源碼對應到Java字節碼的例子
例子前半是Java代碼,後面的註釋是對應的Java字節碼,每行一條指令。每條指令後面我還加了註釋來表示執行完該指令後操作數棧的狀態,就像JVM規範的記法一樣,左邊是棧底右邊是棧頂,省略號表示不關心除棧頂附近幾個值之外操作數棧上的值。
讀取一個局部變量用
local_var_0
// // ... ->
// iload_0 // ..., value0
b: byte
s: short
c: char
i: int
l: long
f: float
d: double
a: 引用類型
存儲一個局部變量用
local_var_0 = ...
// // ..., value0 ->
// istore_0 // ...
合併起來:
local_var_1 = local_var_0;
// // ... ->
// iload_0 // ..., value0 ->
// istore_1 // ...
二元算術運算:
... + ...
// // ..., value1, value2 ->
// iadd // ..., sum
結合讀取局部變量:
local_var_0 + local_var_1
// // ... ->
// iload_0 // ..., value0 ->
// iload_1 // ..., value0, value1 ->
// iadd // ..., sum
結合保存到局部變量:
local_var_2 = local_var_0 + local_var_1;
// // ... ->
// iload_0 // ..., value0 ->
// iload_1 // ..., value0, value1 ->
// iadd // ..., sum ->
// istore_2 // ...
連續加兩次:
local_var_3 = local_var_0 + local_var_1 + local_var_2
// // ... ->
// iload_0 // ..., value0 ->
// iload_1 // ..., value0, value1 ->
// iadd // ..., sum1 ->
// iload_2 // ..., sum1, value2 ->
// iadd // ..., sum2 ->
// istore_3 // ...
返回結果:
return ...;
// // ..., value ->
// ireturn // ...
返回一個局部變量:
return local_var_0;
// // ... ->
// iload_0 // ..., value0 ->
// ireturn // ...
返回一個加法:
return local_var_0 + local_var_0
// // ... ->
// iload_0 // ..., value0 ->
// dup // ..., value0, value0 ->
// iadd // ..., sum ->
// ireturn // ...
1 // iconst_1
true // iconst_1 // JVM的類型系統裡,整型比int窄的類型都統一帶符號擴展到int來表示
127 // bipush 127 // 能用一個字節表示的帶符號整數常量
1234 // sipush 1234 // 能用兩個字節表示的帶符號整數常量
12.5 // ldc 12.5 // 較大的整型常量、float、double、字符串常量用ldc
創建一個對象,用空參數的構造器:
new Object()
// // ... ->
// new java/lang/Object // ..., ref ->
// dup // ..., ref, ref ->
// invokespecial java/lang/Object.
在字節代碼中,Java方法體是由一系列的指令組成的。而要做的是生成調用System.out.println方法的指令,並把這些指令插入到指令集合的最前面。ASM對這些指令做了抽象,不過熟悉全部的指令比較困難。ASM提供了一個工具類ASMifierClassVisitor,可以打印出Java類的字節代碼的結構信息。當需要增強某個類的時候,可以先在源代碼上做出修改,再通過此工具類來比較修改前後的字節代碼的差異,從而確定該如何編寫增強的代碼。
源代碼生成之後,就已經成為了程序的一部分,開發人員需要去維護它:要麼手工修改生成出來的源代碼,要麼重新生成。而字節代碼的增強過程,對於開發人員是完全透明的。妥善使用Java字節代碼的操縱技術,可以更好的解決某一類開發問題。
尚學堂12大精英團隊+各類實戰項目,真正實現1+1>10的目標效果。幫助學員迅速成長,持久騰飛,成就學員“高富帥”人生;幫助企業技術和團隊成長,成就百年中華名企;助力中國持續成為世界強國而貢獻力量。尚學堂12大精英團隊,覆蓋IT行業十大領域,實戰團隊240人,服務學員累計超過10萬人,就業合作企業數量500+。
閱讀更多 Java的筆記 的文章