東莞求職招聘信息網(wǎng)鎮(zhèn)江網(wǎng)站seo
文章目錄
- 局部變量表
- javap
- 字節(jié)碼
- 指令分類
- 指令
- 指令數(shù)據(jù)類型前綴
- 加載和存儲指令
- 加載常量
- 算術(shù)指令
- 其他指令
- 字節(jié)碼示例說明
局部變量表
每個(gè)線程的幀棧是獨(dú)立的,每個(gè)線程中的方法調(diào)用會產(chǎn)生棧幀,棧幀中保存著方法執(zhí)行的信息,例如局部變量表。
局部變量表是一個(gè)數(shù)組,大小在編譯時(shí)就確定了,方法運(yùn)行期間是不會改變局部變量表的大小。
局部變量表是一個(gè)數(shù)組中保存的結(jié)構(gòu)叫做:slot
slot中的變量類型有下面10種(8種基本類型、引用類型、返回地址):
- byte
- bool
- char
- short
- int
- flot
- double
- long
- reference(引用類型)
- returnAddress(返回值地址)
除了long和double會占用2個(gè)slot,其他類型占用1個(gè)slot,byte、short、char、bool類型會轉(zhuǎn)換為int類型存儲。
JVM會為局部變量表中的每一個(gè)slot都分配一個(gè)訪問索引,通過索引訪問到局部變量表中指定的局部變量值。
索引從0開始,如果當(dāng)前幀是由構(gòu)造方法或者實(shí)例方法創(chuàng)建,那么該對象引用this會被存儲在索引為0的slot。
當(dāng)一個(gè)實(shí)例方法被調(diào)用的時(shí)候,它的方法參數(shù)和方法體內(nèi)部定義的局部變量將會按照順序被復(fù)制到局部變量表中的每一個(gè)slot上。
局slot可以重用,如果一個(gè)局部變量過了其作用域,那么在其作用域之后申明的新的局部變量就可以復(fù)用過期局部變量的slot。
局部變量表不存在系統(tǒng)初始化的過程,所以定義局部變量必須手動初始化,這個(gè)編譯時(shí)就能檢查。
只要被局部變量表中直接或間接引用的對象都不會被回收。
javap
javap主要用來做反編譯,可以查看編譯之后的字節(jié)碼,可以看javac處理之后的代碼是什么樣。
通過字節(jié)碼可以看出:做了哪些優(yōu)化,處理了哪些語法糖。
最常見3個(gè)參數(shù):
- -c:查看反編譯方法
- -l(小寫L):-c的基礎(chǔ)上多了局部變量表、指令索引和源碼行號的對應(yīng)關(guān)系
- -v: 所有信息
參數(shù) | 作用說明 |
---|---|
-version | 版本信息 |
-v 或 -verbose | 輸出附加信息 |
-l | 輸出行號和局部變量表 |
-public | 僅顯示公共類和成員 |
-protected | 顯示受保護(hù)的/公共類和成員 |
-package | 顯示程序包/受保護(hù)的/公共類和成員 |
-p 或 -private | 顯示所有類和成員 |
-c | 對代碼進(jìn)行反匯編 |
-s | 輸出簡潔版,只包含方法簽名等基本信息 |
-sysinfo | 顯示正在處理的類的系統(tǒng)信息 |
-constants | 顯示最終常量 |
-classpath path | 指定查找用戶類文件的位置 |
-cp path | 指定查找用戶類文件的位置 |
-bootclasspath path | 覆蓋引導(dǎo)類文件的位置 |
字節(jié)碼
字節(jié)碼執(zhí)行有一個(gè)操作棧,后面說的放入棧頂就是指操作棧頂。
指令分類
- 加載指令(Load):用于把變量從主存加載到棧內(nèi)存
- 存儲指令(Store):用于把變量從棧內(nèi)存存儲到主存
- 棧操作指令(Stack):用于對棧進(jìn)行操作,比如交換棧頂元素,復(fù)制棧頂元素等
- 算術(shù)指令(Arithmetic):用于進(jìn)行算術(shù)運(yùn)算,比如加法,減法,乘法,除法等
- 轉(zhuǎn)換指令(Conversion):用于進(jìn)行類型轉(zhuǎn)換,比如將int類型轉(zhuǎn)為float類型等
- 比較指令(Comparison):用于進(jìn)行數(shù)值比較
- 控制指令(Control):用于進(jìn)行控制流轉(zhuǎn)移
- 引用指令(Reference):用于操作對象,比如創(chuàng)建對象,獲取對象的字段等
- 擴(kuò)展指令(Extended):用于對指令集進(jìn)行擴(kuò)展
- 同步指令(Synchronization):用于線程同步
指令
指令 | 說明 |
---|---|
load | 加載操作,通常表示從局部變量表或數(shù)組中加載一個(gè)值到操作數(shù)棧 |
store | 存儲操作,通常表示將一個(gè)值從操作數(shù)棧存儲到局部變量表或數(shù)組中 |
add | 加運(yùn)算 |
sub | 減運(yùn)算 |
mul | 乘運(yùn)算 |
div | 除運(yùn)算 |
rem | 取余運(yùn)算 |
and | 位與運(yùn)算 |
or | 位或運(yùn)算 |
xor | 異或運(yùn)算 |
neg | 取反操作 |
shl | 左移操作 |
shr | 有符號右移 |
ushr | 無符號右移操作 |
cmpeq | 等于 |
cmpne | 不等于 |
cmplt | 小于 |
cmpge | 大于等于 |
cmpgt | 大于 |
cmple | 小于等于 |
const | 用于表示將常量加載到操作數(shù)棧 |
length | 表示獲取數(shù)組的長度 |
goto | 表示無條件跳轉(zhuǎn) |
if | 表示條件跳轉(zhuǎn) |
return | 表示從方法返回 |
invoke | 表示調(diào)用方法 |
指令數(shù)據(jù)類型前綴
字節(jié)碼指令通常以一個(gè)字符作為前綴,表示操作數(shù)的類型。
指令前綴 | 代表數(shù)據(jù)類型 |
---|---|
i | 表示操作數(shù)是int類型 |
l | 表示操作數(shù)是long類型 |
f | 表示操作數(shù)是float類型 |
d | 表示操作數(shù)是double類型 |
a | 表示操作數(shù)是對象引用類型 |
b | 表示操作數(shù)是byte類型 |
c | 表示操作數(shù)是char類型 |
s | 表示操作數(shù)是short類型 |
例如:iload表示加載一個(gè)int類型的局部變量,fadd表示將兩個(gè)float類型的值相加。
加載和存儲指令
xload_n:局部變量表加載到操作棧
xstore_n:操作棧數(shù)據(jù)存儲到局部變量表
x:可以是i(int、byte、char、short、boolean類型)、l(long類型)、f(float類型)、d(double類型)、a(引用類型)
n:[0,3]
指令 | 描述 |
---|---|
aload_0 | 將局部變量表中索引為0的slot的引用數(shù)據(jù)類型數(shù)據(jù)加載到操作棧頂 |
iload_1 | 將局部變量表中索引為1的slot的int類型數(shù)據(jù)加載到操作棧頂 |
lload_2 | 將局部變量表中索引為2的slot的long類型數(shù)據(jù)加載到操作棧頂 |
fload_3 | 將局部變量表中索引為3的slot的float類型數(shù)據(jù)加載到操作棧頂 |
astore_0 | 將操作棧頂引用類型數(shù)值存入局部變量表中第0個(gè)索引的slot中 |
istore_1 | 將操作棧頂int類型數(shù)據(jù)存入局部變量表中第1個(gè)索引的slot中 |
dstore_2 | 將操作棧頂double類型數(shù)據(jù)存入局部變量表中第2個(gè)索引的slot中 |
lstore_3 | 將操作棧頂long類型數(shù)據(jù)存入局部變量表中第3個(gè)索引的slot中 |
有善于思考的朋友可能就要問了:局部變量表大于4個(gè)怎么辦呢?
使用:
- xload arg:例如 iload 4 表示將局部變量表中索引為4的slot放入棧頂
- xstore arg:例如 istore 4表示將棧頂元素放入局部變量表中索引為4的slot
x:可以是i(int、byte、char、short、boolean類型)、l(long類型)、f(float類型)、d(double類型)、a(引用類型)
加載常量
指令 | 含義 |
---|---|
aconst_null | 將null對象引用壓入棧 |
iconst_m1 | 將int類型常量-1壓入棧 |
iconst_0 | 將int類型常量0壓入棧 |
iconst_1 | 將int類型常量1壓入棧 |
iconst_2 | 將int類型常量2壓入棧 |
iconst_3 | 將int類型常量3壓入棧 |
iconst_4 | 將int類型常量4壓入棧 |
iconst_5 | 將int類型常量5壓入棧 |
lconst_0 | 將long類型常量0壓入棧 |
lconst_1 | 將long類型常量1壓入棧 |
fconst_0 | 將float類型常量0壓入棧 |
fconst_1 | 將float類型常量1壓入棧 |
dconst_0 | 將double類型常量0壓入棧 |
dconst_1 | 將double類型常量1壓入棧 |
bipush | 將一個(gè)byte[-128,127]常量壓入棧 |
sipush | 將short[-32768,32767]常量壓入棧 |
ldc | int, float或String型常量值壓入棧 |
ldc_w | 將int, float或String型常量值壓入棧 |
ldc2_w | 將long、double常量值從常量池壓入棧 |
如果int常量大于6個(gè)怎么整呢?
答案是:
- 小于127使用bipush x,例如:bipush 127
- 大于127小于等于32767使用sipush x,例如:sipush 32767
- 大于32767使用ldc x(常量引用),例如:ldc #31
算術(shù)指令
指令 | 描述 |
---|---|
iadd | 將棧頂兩int類型數(shù)值相加并將結(jié)果壓入棧頂 |
ladd | 將棧頂兩long類型數(shù)值相加并將結(jié)果壓入棧頂 |
fadd | 將棧頂兩float類型數(shù)值相加并將結(jié)果壓入棧頂 |
dadd | 將棧頂兩double類型數(shù)值相加并將結(jié)果壓入棧頂 |
isub | 將棧頂兩int類型數(shù)值相減并將結(jié)果壓入棧頂 |
lsub | 將棧頂兩long類型數(shù)值相減并將結(jié)果壓入棧頂 |
fsub | 將棧頂兩float類型數(shù)值相減并將結(jié)果壓入棧頂 |
dsub | 將棧頂兩double類型數(shù)值相減并將結(jié)果壓入棧頂 |
imul | 將棧頂兩int類型數(shù)值相乘并將結(jié)果壓入棧頂 |
lmul | 將棧頂兩long類型數(shù)值相乘并將結(jié)果壓入棧頂 |
fmul | 將棧頂兩float類型數(shù)值相乘并將結(jié)果壓入棧頂 |
dmul | 將棧頂兩double類型數(shù)值相乘并將結(jié)果壓入棧頂 |
idiv | 將棧頂兩int類型數(shù)值相除并將結(jié)果壓入棧頂 |
ldiv | 將棧頂兩long類型數(shù)值相除并將結(jié)果壓入棧頂 |
fdiv | 將棧頂兩float類型數(shù)值相除并將結(jié)果壓入棧頂 |
ddiv | 將棧頂兩double類型數(shù)值相除并將結(jié)果壓入棧頂 |
其他指令
指令 | 描述 |
---|---|
i2l | 將棧頂int類型數(shù)值轉(zhuǎn)換為long類型并壓入棧頂 |
i2f | 將棧頂int類型數(shù)值轉(zhuǎn)換為float類型并壓入棧頂 |
i2d | 將棧頂int類型數(shù)值轉(zhuǎn)換為double類型并壓入棧頂 |
new | 創(chuàng)建一個(gè)對象,并將引用值壓入棧頂 |
anewarray | 創(chuàng)建一個(gè)引用類型數(shù)組,并將引用值壓入棧頂 |
arraylength | 獲取數(shù)組的長度值,并將長度值壓入棧頂 |
pop | 彈出棧頂數(shù)值 |
pop2 | 彈出棧頂?shù)囊粋€(gè)或兩個(gè)數(shù)值 |
dup | 復(fù)制棧頂數(shù)值并壓入棧頂 |
ifeq | 當(dāng)棧頂int類型數(shù)值等于0時(shí)跳轉(zhuǎn) |
ifne | 當(dāng)棧頂int類型數(shù)值不等于0時(shí)跳轉(zhuǎn) |
goto | 無條件跳轉(zhuǎn) |
invokevirtual | 調(diào)用實(shí)例方法 |
invokespecial | 調(diào)用構(gòu)造函數(shù),私有方法和父類方法 |
invokestatic | 調(diào)用靜態(tài)方法 |
return | 從當(dāng)前方法返回void |
athrow | 將棧頂?shù)漠惓伋?/td> |
monitorenter | 獲取對象的鎖 |
monitorexit | 釋放對象的鎖 |
putfield | 將棧頂?shù)囊粋€(gè)值存儲到對象的字段中 |
getfield | 從對象中取出一個(gè)字段的值 |
字節(jié)碼示例說明
示例類:
public class ByteCodeMain {public static final String HELLO = "HELLO";private Integer score;private String name;public ByteCodeMain(Integer score, String name) {this.score = score;this.name = name;}public int addScore(int add) {return this.score + doubleNum(add);}private static int doubleNum(int add){return add * 2;}public String sayHello(String append) {return HELLO + " " + this.name + append;}public Integer getScore() {return score;}public String getName() {return name;}public static void main(String[] args) {ByteCodeMain byteCodeMain = new ByteCodeMain(10, "Allen");System.out.println(byteCodeMain.getName());System.out.println(byteCodeMain.getScore());int resultNum = byteCodeMain.addScore(20);System.out.println(resultNum);String resultStr = byteCodeMain.sayHello(" 你好啊!");System.out.println(resultStr);System.out.println("常量:" + HELLO);}
}
編譯獲取class文件,然后使用javap反編譯:
javac ByteCodeMain.java
javap -v ByteCodeMain.class
獲取到如下的字節(jié)碼
Classfile ByteCodeMain.classLast modified ; size 2259 bytesSHA-256 checksum 7f96af8a9fec8835a0615c774629e0fcad2e6f00c7afaa33a88eb72cc834fd8fCompiled from "ByteCodeMain.java"
public class vip.meet.base.bytecode.ByteCodeMainminor version: 0major version: 61 // JDK17flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #8 // vip/meet/base/bytecode/ByteCodeMainsuper_class: #2 // java/lang/Objectinterfaces: 0, fields: 3, methods: 7, attributes: 3
Constant pool: // 常量池#1 = Methodref #2.#3 // java/lang/Object."<init>":()V#2 = Class #4 // java/lang/Object#3 = NameAndType #5:#6 // "<init>":()V#4 = Utf8 java/lang/Object#5 = Utf8 <init>#6 = Utf8 ()V#7 = Fieldref #8.#9 // vip/meet/base/bytecode/ByteCodeMain.score:Ljava/lang/Integer;#8 = Class #10 // vip/meet/base/bytecode/ByteCodeMain#9 = NameAndType #11:#12 // score:Ljava/lang/Integer;#10 = Utf8 vip/meet/base/bytecode/ByteCodeMain#11 = Utf8 score#12 = Utf8 Ljava/lang/Integer;#13 = Fieldref #8.#14 // vip/meet/base/bytecode/ByteCodeMain.name:Ljava/lang/String;#14 = NameAndType #15:#16 // name:Ljava/lang/String;#15 = Utf8 name#16 = Utf8 Ljava/lang/String;#17 = Methodref #18.#19 // java/lang/Integer.intValue:()I#18 = Class #20 // java/lang/Integer#19 = NameAndType #21:#22 // intValue:()I#20 = Utf8 java/lang/Integer#21 = Utf8 intValue#22 = Utf8 ()I#23 = Methodref #8.#24 // vip/meet/base/bytecode/ByteCodeMain.doubleNum:(I)I#24 = NameAndType #25:#26 // doubleNum:(I)I#25 = Utf8 doubleNum#26 = Utf8 (I)I#27 = InvokeDynamic #0:#28 // #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;#28 = NameAndType #29:#30 // makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;#29 = Utf8 makeConcatWithConstants#30 = Utf8 (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;#31 = Methodref #18.#32 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;#32 = NameAndType #33:#34 // valueOf:(I)Ljava/lang/Integer;#33 = Utf8 valueOf#34 = Utf8 (I)Ljava/lang/Integer;#35 = String #36 // Allen#36 = Utf8 Allen#37 = Methodref #8.#38 // vip/meet/base/bytecode/ByteCodeMain."<init>":(Ljava/lang/Integer;Ljava/lang/String;)V#38 = NameAndType #5:#39 // "<init>":(Ljava/lang/Integer;Ljava/lang/String;)V#39 = Utf8 (Ljava/lang/Integer;Ljava/lang/String;)V#40 = Fieldref #41.#42 // java/lang/System.out:Ljava/io/PrintStream;#41 = Class #43 // java/lang/System#42 = NameAndType #44:#45 // out:Ljava/io/PrintStream;#43 = Utf8 java/lang/System#44 = Utf8 out#45 = Utf8 Ljava/io/PrintStream;#46 = Methodref #8.#47 // vip/meet/base/bytecode/ByteCodeMain.getName:()Ljava/lang/String;#47 = NameAndType #48:#49 // getName:()Ljava/lang/String;#48 = Utf8 getName#49 = Utf8 ()Ljava/lang/String;#50 = Methodref #51.#52 // java/io/PrintStream.println:(Ljava/lang/String;)V#51 = Class #53 // java/io/PrintStream#52 = NameAndType #54:#55 // println:(Ljava/lang/String;)V#53 = Utf8 java/io/PrintStream#54 = Utf8 println#55 = Utf8 (Ljava/lang/String;)V#56 = Methodref #8.#57 // vip/meet/base/bytecode/ByteCodeMain.getScore:()Ljava/lang/Integer;#57 = NameAndType #58:#59 // getScore:()Ljava/lang/Integer;#58 = Utf8 getScore#59 = Utf8 ()Ljava/lang/Integer;#60 = Methodref #51.#61 // java/io/PrintStream.println:(Ljava/lang/Object;)V#61 = NameAndType #54:#62 // println:(Ljava/lang/Object;)V#62 = Utf8 (Ljava/lang/Object;)V#63 = Methodref #8.#64 // vip/meet/base/bytecode/ByteCodeMain.addScore:(I)I#64 = NameAndType #65:#26 // addScore:(I)I#65 = Utf8 addScore#66 = Methodref #51.#67 // java/io/PrintStream.println:(I)V#67 = NameAndType #54:#68 // println:(I)V#68 = Utf8 (I)V#69 = String #70 // 你好啊!#70 = Utf8 你好啊!#71 = Methodref #8.#72 // vip/meet/base/bytecode/ByteCodeMain.sayHello:(Ljava/lang/String;)Ljava/lang/String;#72 = NameAndType #73:#74 // sayHello:(Ljava/lang/String;)Ljava/lang/String;#73 = Utf8 sayHello#74 = Utf8 (Ljava/lang/String;)Ljava/lang/String;#75 = String #76 // 常量:HELLO#76 = Utf8 常量:HELLO#77 = Utf8 HELLO#78 = Utf8 ConstantValue#79 = String #77 // HELLO#80 = Utf8 Code#81 = Utf8 LineNumberTable#82 = Utf8 LocalVariableTable#83 = Utf8 this#84 = Utf8 Lvip/meet/base/bytecode/ByteCodeMain;#85 = Utf8 MethodParameters#86 = Utf8 add#87 = Utf8 I#88 = Utf8 append#89 = Utf8 main#90 = Utf8 ([Ljava/lang/String;)V#91 = Utf8 args#92 = Utf8 [Ljava/lang/String;#93 = Utf8 byteCodeMain#94 = Utf8 resultNum#95 = Utf8 resultStr#96 = Utf8 SourceFile#97 = Utf8 ByteCodeMain.java#98 = Utf8 BootstrapMethods#99 = String #100 // HELLO \u0001\u0001#100 = Utf8 HELLO \u0001\u0001#101 = MethodHandle 6:#102 // REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#102 = Methodref #103.#104 // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#103 = Class #105 // java/lang/invoke/StringConcatFactory#104 = NameAndType #29:#106 // makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#105 = Utf8 java/lang/invoke/StringConcatFactory#106 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;#107 = Utf8 InnerClasses#108 = Class #109 // java/lang/invoke/MethodHandles$Lookup#109 = Utf8 java/lang/invoke/MethodHandles$Lookup#110 = Class #111 // java/lang/invoke/MethodHandles#111 = Utf8 java/lang/invoke/MethodHandles#112 = Utf8 Lookup
{public static final java.lang.String HELLO;descriptor: Ljava/lang/String;flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINALConstantValue: String HELLOpublic vip.meet.base.bytecode.ByteCodeMain(java.lang.Integer, java.lang.String);descriptor: (Ljava/lang/Integer;Ljava/lang/String;)V // 構(gòu)造函數(shù)flags: (0x0001) ACC_PUBLICCode:stack=2, locals=3, args_size=30: aload_0 // 加載局部變量表索引為0的slot數(shù)據(jù)到棧頂,this1: invokespecial #1 // 調(diào)用Object的構(gòu)造函數(shù),Method java/lang/Object."<init>":()V4: aload_0 // 加載局部變量表索引為0的slot數(shù)據(jù)到棧頂,this5: aload_1 // 加載局部變量表索引為1的slot數(shù)據(jù)到棧頂,Integer(score)6: putfield #7 // 將棧頂元素score設(shè)置到對象變量,Field score:Ljava/lang/Integer;9: aload_0 // 加載局部變量表索引為0的slot數(shù)據(jù)到棧頂,this10: aload_2 // 加載局部變量表索引為2的slot數(shù)據(jù)到棧頂,String(name)11: putfield #13 // 將棧頂元素name設(shè)置到對象變量,Field name:Ljava/lang/String;14: returnLineNumberTable:line 13: 0line 14: 4line 15: 9line 16: 14LocalVariableTable: // 局部變量表Start Length Slot Name Signature0 15 0 this Lvip/meet/base/bytecode/ByteCodeMain;0 15 1 score Ljava/lang/Integer;0 15 2 name Ljava/lang/String;MethodParameters:Name Flagsscorenamepublic int addScore(int);descriptor: (I)Iflags: (0x0001) ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_0 // 加載局部變量表索引為0的slot數(shù)據(jù)到棧頂,this1: getfield #7 // 獲取對象變量放入棧頂,Field score:Ljava/lang/Integer;4: invokevirtual #17 // 調(diào)用對象方法(將int轉(zhuǎn)為Integer對象),Method java/lang/Integer.intValue:()I7: iload_1 // 加載局部變量表索引為1的slot數(shù)據(jù)到棧頂,add8: invokestatic #23 // 調(diào)用靜態(tài)方法,Method doubleNum:(I)I11: iadd // 將棧頂2元素相加之和放入棧頂12: ireturn // 返回int類型LineNumberTable:line 19: 0LocalVariableTable:Start Length Slot Name Signature0 13 0 this Lvip/meet/base/bytecode/ByteCodeMain;0 13 1 add IMethodParameters:Name Flagsaddpublic java.lang.String sayHello(java.lang.String);descriptor: (Ljava/lang/String;)Ljava/lang/String;flags: (0x0001) ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_0 // 加載局部變量表索引為0的slot數(shù)據(jù)到棧頂,this1: getfield #13 // 獲取對象變量放入棧頂,Field name:Ljava/lang/String;4: aload_1 // 加載局部變量表索引為1的slot數(shù)據(jù)到棧頂,append5: invokedynamic #27, 0 // 調(diào)用動態(tài)方法,InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;10: areturnLineNumberTable:line 27: 0LocalVariableTable:Start Length Slot Name Signature0 11 0 this Lvip/meet/base/bytecode/ByteCodeMain;0 11 1 append Ljava/lang/String;MethodParameters:Name Flagsappendpublic java.lang.Integer getScore();descriptor: ()Ljava/lang/Integer;flags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: getfield #7 // Field score:Ljava/lang/Integer;4: areturnLineNumberTable:line 31: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lvip/meet/base/bytecode/ByteCodeMain;public java.lang.String getName();descriptor: ()Ljava/lang/String;flags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: getfield #13 // Field name:Ljava/lang/String;4: areturnLineNumberTable:line 35: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lvip/meet/base/bytecode/ByteCodeMain;public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: (0x0009) ACC_PUBLIC, ACC_STATICCode:stack=4, locals=4, args_size=10: new #8 // 創(chuàng)建ByteCodeMain對象,并放入棧頂,class vip/meet/base/bytecode/ByteCodeMain3: dup // 復(fù)制棧頂元素并壓入棧頂4: bipush 10 // 將byte類型常量10壓入棧頂,字面量常量10被處理成了一個(gè)字節(jié)的byte類型6: invokestatic #31 // 調(diào)用靜態(tài)方法,Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: ldc #35 // 將常量池#35常量放入棧頂,String Allen11: invokespecial #37 // 調(diào)用構(gòu)造方法,Method "<init>":(Ljava/lang/Integer;Ljava/lang/String;)V14: astore_1 // 將棧頂元素(上一步構(gòu)建的ByteCodeMain對象)放入局部變量表索引為1的slot15: getstatic #40 // 獲取靜態(tài)變量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;18: aload_1 // 加載局部變量表索引為1的slot數(shù)據(jù)到棧頂,ByteCodeMain對象19: invokevirtual #46 // 調(diào)用實(shí)例方法,Method getName:()Ljava/lang/String;22: invokevirtual #50 // 調(diào)用實(shí)例方法,Method java/io/PrintStream.println:(Ljava/lang/String;)V25: getstatic #40 // 獲取靜態(tài)變量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;28: aload_1 // 加載局部變量表索引為1的slot數(shù)據(jù)到棧頂,ByteCodeMain對象29: invokevirtual #56 // 調(diào)用實(shí)例方法,Method getScore:()Ljava/lang/Integer;32: invokevirtual #60 // 調(diào)用實(shí)例方法,Method java/io/PrintStream.println:(Ljava/lang/Object;)V35: aload_1 // 加載局部變量表索引為1的slot數(shù)據(jù)到棧頂,ByteCodeMain對象36: bipush 20 // 將byte類型常量20壓入棧頂,字面量常量20被處理成了一個(gè)字節(jié)的byte類型38: invokevirtual #63 // 調(diào)用實(shí)例方法,Method addScore:(I)I41: istore_2 // 將棧頂元素(上一步addScore計(jì)算獲得的值)放入局部變量表索引為2的slot42: getstatic #40 // 獲取靜態(tài)變量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;45: iload_2 // 加載局部變量表索引為2的slot數(shù)據(jù)到棧頂,resultNum46: invokevirtual #66 // 調(diào)用實(shí)例方法,Method java/io/PrintStream.println:(I)V49: aload_1 // 加載局部變量表索引為1的slot數(shù)據(jù)到棧頂,ByteCodeMain對象50: ldc #69 // 將常量池#69常量放入棧頂,String 你好啊!52: invokevirtual #71 // 調(diào)用實(shí)例方法,Method sayHello:(Ljava/lang/String;)Ljava/lang/String;55: astore_3 // 將棧頂元素(sayHello方法返回值)放入局部變量表索引為3的slot,resultStr56: getstatic #40 // 獲取靜態(tài)變量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;59: aload_3 // 加載局部變量表索引為3的slot數(shù)據(jù)到棧頂,resultStr60: invokevirtual #50 // 調(diào)用實(shí)例方法,Method java/io/PrintStream.println:(Ljava/lang/String;)V63: getstatic #40 // 獲取靜態(tài)變量(System.out),Field java/lang/System.out:Ljava/io/PrintStream;66: ldc #75 // 將常量池#75常量放入棧頂,String 常量:HELLO68: invokevirtual #50 // 調(diào)用實(shí)例方法,Method java/io/PrintStream.println:(Ljava/lang/String;)V71: returnLineNumberTable:line 39: 0line 40: 15line 41: 25line 42: 35line 43: 42line 44: 49line 45: 56line 46: 63line 47: 71LocalVariableTable:Start Length Slot Name Signature0 72 0 args [Ljava/lang/String;15 57 1 byteCodeMain Lvip/meet/base/bytecode/ByteCodeMain;42 30 2 resultNum I56 16 3 resultStr Ljava/lang/String;MethodParameters:Name Flagsargs
}
SourceFile: "ByteCodeMain.java"
BootstrapMethods:0: #101 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;Method arguments:#99 HELLO \u0001\u0001
InnerClasses:public static final #112= #108 of #110; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles