日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

我要悄悄学习 Java 字节码指令,在成为技术大佬的路上一去不复返

發(fā)布時間:2023/12/31 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 我要悄悄学习 Java 字节码指令,在成为技术大佬的路上一去不复返 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

大家好,我是二哥呀。

Java 字節(jié)碼指令是 JVM 體系中非常難啃的一塊硬骨頭,我估計(jì)有些讀者會有這樣的疑惑,“Java 字節(jié)碼難學(xué)嗎?我能不能學(xué)會啊?”

講良心話,不是我謙虛,一開始學(xué) Java 字節(jié)碼和 Java 虛擬機(jī)方面的知識我也感覺頭大!但硬著頭皮學(xué)了一陣子之后,突然就開竅了,覺得好有意思,尤其是明白了 Java 代碼在底層竟然是這樣執(zhí)行的時候,感覺既膨脹又飄飄然,渾身上下散發(fā)著自信的光芒!

我在 CSDN 共輸出了 100 多篇 Java 方面的文章,總字?jǐn)?shù)超過 30 萬字, 內(nèi)容風(fēng)趣幽默、通俗易懂,收獲了很多初學(xué)者的認(rèn)可和支持,內(nèi)容包括 Java 語法、Java 集合框架、Java 并發(fā)編程、Java 虛擬機(jī)等核心內(nèi)容

為了幫助更多的 Java 初學(xué)者,我“一怒之下”就把這些文章重新整理并開源到了 GitHub,起名《教妹學(xué) Java》,聽起來是不是就很有趣?

GitHub 開源地址(歡迎 star):https://github.com/itwanger/jmx-java

Java 官方的虛擬機(jī) Hotspot 是基于棧的,而不是基于寄存器的。

基于棧的優(yōu)點(diǎn)是可移植性更好、指令更短、實(shí)現(xiàn)起來簡單,但不能隨機(jī)訪問棧中的元素,完成相同功能所需要的指令數(shù)也比寄存器的要多,需要頻繁的入棧和出棧。

基于寄存器的優(yōu)點(diǎn)是速度快,有利于程序運(yùn)行速度的優(yōu)化,但操作數(shù)需要顯式指定,指令也比較長。

Java 字節(jié)碼由操作碼和操作數(shù)組成。

  • 操作碼(Opcode):一個字節(jié)長度(0-255,意味著指令集的操作碼總數(shù)不可能超過 256 條),代表著某種特定的操作含義。
  • 操作數(shù)(Operands):零個或者多個,緊跟在操作碼之后,代表此操作需要的參數(shù)。

由于 Java 虛擬機(jī)是基于棧而不是寄存器的結(jié)構(gòu),所以大多數(shù)指令都只有一個操作碼。比如 aload_0(將局部變量表中下標(biāo)為 0 的數(shù)據(jù)壓入操作數(shù)棧中)就只有操作碼沒有操作數(shù),而 invokespecial #1(調(diào)用成員方法或者構(gòu)造方法,并傳遞常量池中下標(biāo)為 1 的常量)就是由操作碼和操作數(shù)組成的。

01、加載與存儲指令

加載(load)和存儲(store)相關(guān)的指令是使用最頻繁的指令,用于將數(shù)據(jù)從棧幀的局部變量表和操作數(shù)棧之間來回傳遞。

1)將局部變量表中的變量壓入操作數(shù)棧中

  • xload_(x 為 i、l、f、d、a,n 默認(rèn)為 0 到 3),表示將第 n 個局部變量壓入操作數(shù)棧中。
  • xload(x 為 i、l、f、d、a),通過指定參數(shù)的形式,將局部變量壓入操作數(shù)棧中,當(dāng)使用這個指令時,表示局部變量的數(shù)量可能超過了 4 個

解釋一下。

x 為操作碼助記符,表明是哪一種數(shù)據(jù)類型。見下表所示。

像 arraylength 指令,沒有操作碼助記符,它沒有代表數(shù)據(jù)類型的特殊字符,但操作數(shù)只能是一個數(shù)組類型的對象。

大部分的指令都不支持 byte、short 和 char,甚至沒有任何指令支持 boolean 類型。編譯器會將 byte 和 short 類型的數(shù)據(jù)帶符號擴(kuò)展(Sign-Extend)為 int 類型,將 boolean 和 char 零位擴(kuò)展(Zero-Extend)為 int 類型。

舉例來說。

private void load(int age, String name, long birthday, boolean sex) {System.out.println(age + name + birthday + sex); }

通過 jclasslib 看一下 load() 方法(4 個參數(shù))的字節(jié)碼指令。

  • iload_1:將局部變量表中下標(biāo)為 1 的 int 變量壓入操作數(shù)棧中。
  • aload_2:將局部變量表中下標(biāo)為 2 的引用數(shù)據(jù)類型變量(此時為 String)壓入操作數(shù)棧中。
  • lload_3:將局部變量表中下標(biāo)為 3 的 long 型變量壓入操作數(shù)棧中。
  • iload 5:將局部變量表中下標(biāo)為 5 的 int 變量(實(shí)際為 boolean)壓入操作數(shù)棧中。

通過查看局部變量表就能關(guān)聯(lián)上了。

2)將常量池中的常量壓入操作數(shù)棧中

根據(jù)數(shù)據(jù)類型和入棧內(nèi)容的不同,此類又可以細(xì)分為 const 系列、push 系列和 Idc 指令。

const 系列,用于特殊的常量入棧,要入棧的常量隱含在指令本身。

push 系列,主要包括 bipush 和 sipush,前者接收 8 位整數(shù)作為參數(shù),后者接收 16 位整數(shù)。

Idc 指令,當(dāng) const 和 push 不能滿足的時候,萬能的 Idc 指令就上場了,它接收一個 8 位的參數(shù),指向常量池中的索引。

  • Idc_w:接收兩個 8 位數(shù),索引范圍更大。
  • 如果參數(shù)是 long 或者 double,使用 Idc2_w 指令。

舉例來說。

public void pushConstLdc() {// 范圍 [-1,5]int iconst = -1;// 范圍 [-128,127]int bipush = 127;// 范圍 [-32768,32767]int sipush= 32767;// 其他 intint ldc = 32768;String aconst = null;String IdcString = "沉默王二"; }

通過 jclasslib 看一下 pushConstLdc() 方法的字節(jié)碼指令。

  • iconst_m1:將 -1 入棧。范圍 [-1,5]。
  • bipush 127:將 127 入棧。范圍 [-128,127]。
  • sipush 32767:將 32767 入棧。范圍 [-32768,32767]。
  • ldc #6 <32768>:將常量池中下標(biāo)為 6 的常量 32768 入棧。
  • aconst_null:將 null 入棧。
  • ldc #7 <沉默王二>:將常量池中下標(biāo)為 7 的常量“沉默王二”入棧。

3)將棧頂?shù)臄?shù)據(jù)出棧并裝入局部變量表中

主要是用來給局部變量賦值,這類指令主要以 store 的形式存在。

  • xstore_(x 為 i、l、f、d、a,n 默認(rèn)為 0 到 3)
  • xstore(x 為 i、l、f、d、a)

明白了 xload_ 和 xload,再看 xstore_ 和 xstore 就會輕松得多,作用反了一下而已。

大家來想一個問題,為什么要有 xstore_ 和 xload_ 呢?它們的作用和 xstore n、xload n 不是一樣的嗎?

xstore_ 和 xstore n 的區(qū)別在于,前者相當(dāng)于只有操作碼,占用 1 個字節(jié);后者相當(dāng)于由操作碼和操作數(shù)組成,操作碼占 1 個字節(jié),操作數(shù)占 2 個字節(jié),一共占 3 個字節(jié)。

由于局部變量表中前幾個位置總是非常常用,雖然 xstore_<n> 和 xload_<n> 增加了指令數(shù)量,但字節(jié)碼的體積變小了!

舉例來說。

public void store(int age, String name) {int temp = age + 2;String str = name; }

通過 jclasslib 看一下 store() 方法的字節(jié)碼指令。

  • istore_3:從操作數(shù)中彈出一個整數(shù),并把它賦值給局部變量表中索引為 3 的變量。
  • astore 4:從操作數(shù)中彈出一個引用數(shù)據(jù)類型,并把它賦值給局部變量表中索引為 4 的變量。

通過查看局部變量表就能關(guān)聯(lián)上了。

02、算術(shù)指令

算術(shù)指令用于對兩個操作數(shù)棧上的值進(jìn)行某種特定運(yùn)算,并把結(jié)果重新壓入操作數(shù)棧。可以分為兩類:整型數(shù)據(jù)的運(yùn)算指令和浮點(diǎn)數(shù)據(jù)的運(yùn)算指令。

需要注意的是,數(shù)據(jù)運(yùn)算可能會導(dǎo)致溢出,比如兩個很大的正整數(shù)相加,很可能會得到一個負(fù)數(shù)。但 Java 虛擬機(jī)規(guī)范中并沒有對這種情況給出具體結(jié)果,因此程序是不會顯式報(bào)錯的。所以,大家在開發(fā)過程中,如果涉及到較大的數(shù)據(jù)進(jìn)行加法、乘法運(yùn)算的時候,一定要注意!

當(dāng)發(fā)生溢出時,將會使用有符號的無窮大 Infinity 來表示;如果某個操作結(jié)果沒有明確的數(shù)學(xué)定義的話,將會使用 NaN 值來表示。而且所有使用 NaN 作為操作數(shù)的算術(shù)操作,結(jié)果都會返回 NaN。

舉例來說。

public void infinityNaN() {int i = 10;double j = i / 0.0;System.out.println(j); // Infinitydouble d1 = 0.0;double d2 = d1 / 0.0;System.out.println(d2); // NaN }
  • 任何一個非零的數(shù)除以浮點(diǎn)數(shù) 0(注意不是 int 類型),可以想象結(jié)果是無窮大 Infinity 的。
  • 把這個非零的數(shù)換成 0 的時候,結(jié)果又不太好定義,就用 NaN 值來表示。

Java 虛擬機(jī)提供了兩種運(yùn)算模式

  • 向最接近數(shù)舍入:在進(jìn)行浮點(diǎn)數(shù)運(yùn)算時,所有的結(jié)果都必須舍入到一個適當(dāng)?shù)木?#xff0c;不是特別精確的結(jié)果必須舍入為可被表示的最接近的精確值,如果有兩種可表示的形式與該值接近,將優(yōu)先選擇最低有效位為零的(類似四舍五入)。
  • 向零舍入:將浮點(diǎn)數(shù)轉(zhuǎn)換為整數(shù)時,采用該模式,該模式將在目標(biāo)數(shù)值類型中選擇一個最接近但是不大于原值的數(shù)字作為最精確的舍入結(jié)果(類似取整)。

我把所有的算術(shù)指令列一下:

  • 加法指令:iadd、ladd、fadd、dadd
  • 減法指令:isub、lsub、fsub、dsub
  • 乘法指令:imul、lmul、fmul、dmul
  • 除法指令:idiv、ldiv、fdiv、ddiv
  • 求余指令:irem、lrem、frem、drem
  • 自增指令:iinc

舉例來說。

public void calculate(int age) {int add = age + 1;int sub = age - 1;int mul = age * 2;int div = age / 3;int rem = age % 4;age++;age--; }

通過 jclasslib 看一下 calculate() 方法的字節(jié)碼指令。

  • iadd,加法
  • isub,減法
  • imul,乘法
  • idiv,除法
  • irem,取余
  • iinc,自增的時候 +1,自減的時候 -1

03、類型轉(zhuǎn)換指令

可以分為兩種:

1)寬化,小類型向大類型轉(zhuǎn)換,比如 int–>long–>float–>double,對應(yīng)的指令有:i2l、i2f、i2d、l2f、l2d、f2d。

  • 從 int 到 long,或者從 int 到 double,是不會有精度丟失的;
  • 從 int、long 到 float,或者 long 到 double 時,可能會發(fā)生精度丟失;
  • 從 byte、char 和 short 到 int 的寬化類型轉(zhuǎn)換實(shí)際上是隱式發(fā)生的,這樣可以減少字節(jié)碼指令,畢竟字節(jié)碼指令只有 256 個,占一個字節(jié)。

2)窄化,大類型向小類型轉(zhuǎn)換,比如從 int 類型到 byte、short 或者 char,對應(yīng)的指令有:i2b、i2s、i2c;從 long 到 int,對應(yīng)的指令有:l2i;從 float 到 int 或者 long,對應(yīng)的指令有:f2i、f2l;從 double 到 int、long 或者 float,對應(yīng)的指令有:d2i、d2l、d2f。

  • 窄化很可能會發(fā)生精度丟失,畢竟是不同的數(shù)量級;
  • 但 Java 虛擬機(jī)并不會因此拋出運(yùn)行時異常。

舉例來說。

public void updown() {int i = 10;double d = i;float f = 10f;long ong = (long)f; }

通過 jclasslib 看一下 updown() 方法的字節(jié)碼指令。

  • i2d,int 寬化為 double
  • f2l, float 窄化為 long

04、對象的創(chuàng)建和訪問指令

Java 是一門面向?qū)ο蟮木幊陶Z言,那么 Java 虛擬機(jī)是如何從字節(jié)碼層面進(jìn)行支持的呢?

1)創(chuàng)建指令

數(shù)組也是一種對象,但它創(chuàng)建的字節(jié)碼指令和普通的對象不同。創(chuàng)建數(shù)組的指令有三種:

  • newarray:創(chuàng)建基本數(shù)據(jù)類型的數(shù)組
  • anewarray:創(chuàng)建引用類型的數(shù)組
  • multianewarray:創(chuàng)建多維數(shù)組

普通對象的創(chuàng)建指令只有一個,就是 new,它會接收一個操作數(shù),指向常量池中的一個索引,表示要創(chuàng)建的類型。

舉例來說。

public void newObject() {String name = new String("沉默王二");File file = new File("無愁河的浪蕩漢子.book");int [] ages = {}; }

通過 jclasslib 看一下 newObject() 方法的字節(jié)碼指令。

  • new #13 <java/lang/String>,創(chuàng)建一個 String 對象。
  • new #15 <java/io/File>,創(chuàng)建一個 File 對象。
  • newarray 10 (int),創(chuàng)建一個 int 類型的數(shù)組。

2)字段訪問指令

字段可以分為兩類,一類是成員變量,一類是靜態(tài)變量(static 關(guān)鍵字修飾的),所以字段訪問指令可以分為兩類:

  • 訪問靜態(tài)變量:getstatic、putstatic。
  • 訪問成員變量:getfield、putfield,需要創(chuàng)建對象后才能訪問。

舉例來說。

public class Writer {private String name;static String mark = "作者";public static void main(String[] args) {print(mark);Writer w = new Writer();print(w.name);}public static void print(String arg) {System.out.println(arg);} }

通過 jclasslib 看一下 main() 方法的字節(jié)碼指令。

  • getstatic #2 <com/itwanger/jvm/Writer.mark>,訪問靜態(tài)變量 mark
  • getfield #6 <com/itwanger/jvm/Writer.name>,訪問成員變量 name

05、方法調(diào)用和返回指令

方法調(diào)用指令有 5 個,分別用于不同的場景:

  • invokevirtual:用于調(diào)用對象的成員方法,根據(jù)對象的實(shí)際類型進(jìn)行分派,支持多態(tài)。
  • invokeinterface:用于調(diào)用接口方法,會在運(yùn)行時搜索由特定對象實(shí)現(xiàn)的接口方法進(jìn)行調(diào)用。
  • invokespecial:用于調(diào)用一些需要特殊處理的方法,包括構(gòu)造方法、私有方法和父類方法。
  • invokestatic:用于調(diào)用靜態(tài)方法。
  • invokedynamic:用于在運(yùn)行時動態(tài)解析出調(diào)用點(diǎn)限定符所引用的方法,并執(zhí)行。

舉例來說。

public class InvokeExamples {private void run() {List ls = new ArrayList();ls.add("難頂");ArrayList als = new ArrayList();als.add("學(xué)不動了");}public static void print() {System.out.println("invokestatic");}public static void main(String[] args) {print();InvokeExamples invoke = new InvokeExamples();invoke.run();} }

我們用 javap -c InvokeExamples.class 來反編譯一下。

Compiled from "InvokeExamples.java" public class com.itwanger.jvm.InvokeExamples {public com.itwanger.jvm.InvokeExamples();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnprivate void run();Code:0: new #2 // class java/util/ArrayList3: dup4: invokespecial #3 // Method java/util/ArrayList."<init>":()V7: astore_18: aload_19: ldc #4 // String 難頂11: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z16: pop17: new #2 // class java/util/ArrayList20: dup21: invokespecial #3 // Method java/util/ArrayList."<init>":()V24: astore_225: aload_226: ldc #6 // String 學(xué)不動了28: invokevirtual #7 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z31: pop32: returnpublic static void print();Code:0: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc #9 // String invokestatic5: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: returnpublic static void main(java.lang.String[]);Code:0: invokestatic #11 // Method print:()V3: new #12 // class com/itwanger/jvm/InvokeExamples6: dup7: invokespecial #13 // Method "<init>":()V10: astore_111: aload_112: invokevirtual #14 // Method run:()V15: return }

InvokeExamples 類有 4 個方法,包括缺省的構(gòu)造方法在內(nèi)。

1)InvokeExamples() 構(gòu)造方法中

缺省的構(gòu)造方法內(nèi)部會調(diào)用超類 Object 的初始化構(gòu)造方法:

`invokespecial #1 // Method java/lang/Object."<init>":()V`

2)成員方法 run() 中

invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z

由于 ls 變量的引用類型為接口 List,所以 ls.add() 調(diào)用的是 invokeinterface 指令,等運(yùn)行時再確定是不是接口 List 的實(shí)現(xiàn)對象 ArrayList 的 add() 方法。

invokevirtual #7 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z

由于 als 變量的引用類型已經(jīng)確定為 ArrayList,所以 als.add() 方法調(diào)用的是 invokevirtual 指令。

3)main() 方法中

invokestatic #11 // Method print:()V

print() 方法是靜態(tài)的,所以調(diào)用的是 invokestatic 指令。

方法返回指令根據(jù)方法的返回值類型進(jìn)行區(qū)分,常見的返回指令見下圖。

06、操作數(shù)棧管理指令

常見的操作數(shù)棧管理指令有 pop、dup 和 swap。

  • 將一個或兩個元素從棧頂彈出,并且直接廢棄,比如 pop,pop2;
  • 復(fù)制棧頂?shù)囊粋€或兩個數(shù)值并將其重新壓入棧頂,比如 dup,dup2,dup_×1,dup2_×1,dup_×2,dup2_×2;
  • 將棧最頂端的兩個槽中的數(shù)值交換位置,比如 swap。

這些指令不需要指明數(shù)據(jù)類型,因?yàn)槭前凑瘴恢脡喝牒蛷棾龅摹?/p>

舉例來說。

public class Dup {int age;public int incAndGet() {return ++age;} }

通過 jclasslib 看一下 incAndGet() 方法的字節(jié)碼指令。

  • aload_0:將 this 入棧。
  • dup:復(fù)制棧頂?shù)?this。
  • getfield #2:將常量池中下標(biāo)為 2 的常量加載到棧上,同時將一個 this 出棧。
  • iconst_1:將常量 1 入棧。
  • iadd:將棧頂?shù)膬蓚€值相加后出棧,并將結(jié)果放回棧上。
  • dup_x1:復(fù)制棧頂?shù)脑?#xff0c;并將其插入 this 下面。
  • putfield #2: 將棧頂?shù)膬蓚€元素出棧,并將其賦值給字段 age。
  • ireturn:將棧頂?shù)脑爻鰲7祷亍?/li>

07、控制轉(zhuǎn)移指令

控制轉(zhuǎn)移指令包括:

  • 比較指令,比較棧頂?shù)膬蓚€元素的大小,并將比較結(jié)果入棧。
  • 條件跳轉(zhuǎn)指令,通常和比較指令一塊使用,在條件跳轉(zhuǎn)指令執(zhí)行前,一般先用比較指令進(jìn)行棧頂元素的比較,然后進(jìn)行條件跳轉(zhuǎn)。
  • 比較條件轉(zhuǎn)指令,類似于比較指令和條件跳轉(zhuǎn)指令的結(jié)合體,它將比較和跳轉(zhuǎn)兩個步驟合二為一。
  • 多條件分支跳轉(zhuǎn)指令,專為 switch-case 語句設(shè)計(jì)的。
  • 無條件跳轉(zhuǎn)指令,目前主要是 goto 指令。

1)比較指令

比較指令有:dcmpg,dcmpl、fcmpg、fcmpl、lcmp,指令的第一個字母代表的含義分別是 double、float、long。注意,沒有 int 類型。

對于 double 和 float 來說,由于 NaN 的存在,有兩個版本的比較指令。拿 float 來說,有 fcmpg 和 fcmpl,區(qū)別在于,如果遇到 NaN,fcmpg 會將 1 壓入棧,fcmpl 會將 -1 壓入棧。

舉例來說。

public void lcmp(long a, long b) {if(a > b){} }

通過 jclasslib 看一下 lcmp() 方法的字節(jié)碼指令。

lcmp 用于兩個 long 型的數(shù)據(jù)進(jìn)行比較。

2)條件跳轉(zhuǎn)指令

這些指令都會接收兩個字節(jié)的操作數(shù),它們的統(tǒng)一含義是,彈出棧頂元素,測試它是否滿足某一條件,滿足的話,跳轉(zhuǎn)到對應(yīng)位置。

對于 long、float 和 double 類型的條件分支比較,會先執(zhí)行比較指令返回一個整形值到操作數(shù)棧中后再執(zhí)行 int 類型的條件跳轉(zhuǎn)指令。

對于 boolean、byte、char、short,以及 int,則直接使用條件跳轉(zhuǎn)指令來完成。

舉例來說。

public void fi() {int a = 0;if (a == 0) {a = 10;} else {a = 20;} }

通過 jclasslib 看一下 fi() 方法的字節(jié)碼指令。

3 ifne 12 (+9) 的意思是,如果棧頂?shù)脑夭坏扔?0,跳轉(zhuǎn)到第 12(3+9)行 12 bipush 20。

3)比較條件轉(zhuǎn)指令

前綴“if_”后,以字符“i”開頭的指令針對 int 型整數(shù)進(jìn)行操作,以字符“a”開頭的指令表示對象的比較。

舉例來說。

public void compare() {int i = 10;int j = 20;System.out.println(i > j); }

通過 jclasslib 看一下 compare() 方法的字節(jié)碼指令。

11 if_icmple 18 (+7) 的意思是,如果棧頂?shù)膬蓚€ int 類型的數(shù)值比較的話,如果前者小于后者時跳轉(zhuǎn)到第 18 行(11+7)。

4)多條件分支跳轉(zhuǎn)指令

主要有 tableswitch 和 lookupswitch,前者要求多個條件分支值是連續(xù)的,它內(nèi)部只存放起始值和終止值,以及若干個跳轉(zhuǎn)偏移量,通過給定的操作數(shù) index,可以立即定位到跳轉(zhuǎn)偏移量位置,因此效率比較高;后者內(nèi)部存放著各個離散的 case-offset 對,每次執(zhí)行都要搜索全部的 case-offset 對,找到匹配的 case 值,并根據(jù)對應(yīng)的 offset 計(jì)算跳轉(zhuǎn)地址,因此效率較低。

舉例來說。

public void switchTest(int select) {int num;switch (select) {case 1:num = 10;break;case 2:case 3:num = 30;break;default:num = 40;} }

通過 jclasslib 看一下 switchTest() 方法的字節(jié)碼指令。

case 2 的時候沒有 break,所以 case 2 和 case 3 是連續(xù)的,用的是 tableswitch。如果等于 1,跳轉(zhuǎn)到 28 行;如果等于 2 和 3,跳轉(zhuǎn)到 34 行,如果是 default,跳轉(zhuǎn)到 40 行。

5)無條件跳轉(zhuǎn)指令

goto 指令接收兩個字節(jié)的操作數(shù),共同組成一個帶符號的整數(shù),用于指定指令的偏移量,指令執(zhí)行的目的就是跳轉(zhuǎn)到偏移量給定的位置處。

前面的例子里都出現(xiàn)了 goto 的身影,也很好理解。如果指令的偏移量特別大,超出了兩個字節(jié)的范圍,可以使用指令 goto_w,接收 4 個字節(jié)的操作數(shù)。


巨人的肩膀:

https://segmentfault.com/a/1190000037628881

除了以上這些指令,還有異常處理指令和同步控制指令,我打算吊一吊大家的胃口,大家可以期待一波~~

(騷操作)

路漫漫其修遠(yuǎn)兮,吾將上下而求索

想要走得更遠(yuǎn),Java 字節(jié)碼這塊就必須得硬碰硬地吃透,希望二哥的這些分享可以幫助到大家~

叨逼叨

二哥在 CSDN 上寫了很多 Java 方面的系列文章,有 Java 核心語法、Java 集合框架、Java IO、Java 并發(fā)編程、Java 虛擬機(jī)等,也算是體系完整了。

為了能幫助到更多的 Java 初學(xué)者,二哥把自己連載的《教妹學(xué)Java》開源到了 GitHub,盡管只整理了 50 篇,發(fā)現(xiàn)字?jǐn)?shù)已經(jīng)來到了 10 萬+,內(nèi)容更是沒得說,通俗易懂、風(fēng)趣幽默、圖文并茂

GitHub 開源地址(歡迎 star):https://github.com/itwanger/jmx-java

如果有幫助的話,還請給二哥點(diǎn)個贊,這將是我繼續(xù)分享下去的最強(qiáng)動力!

總結(jié)

以上是生活随笔為你收集整理的我要悄悄学习 Java 字节码指令,在成为技术大佬的路上一去不复返的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲第一免费 | 亚洲免费天堂 | 白嫩少妇激情无码 | 98色| 国产视频亚洲 | 免费在线观看网址入口 | 中文久久久 | 成人一级免费视频 | 精品无码一级毛片免费 | 亚洲男人网 | 男人的天堂在线视频 | 娇小萝被两个黑人用半米长 | 久久视频热 | 亚洲自拍偷拍第一页 | 伊人国产在线观看 | 台湾a级艳片潘金莲 | 中文字幕精品在线视频 | 欧美狂猛xxxxx乱大交3 | 日韩久久久久久久久久 | 国产精选中文字幕 | 雷电将军和丘丘人繁衍后代视频 | 亚洲涩网 | 免费欧美大片 | 国产av无码专区亚洲av | 天天做天天躁天天躁 | 天堂综合网 | 色视频网| 2019天天干天天操 | 五月婷婷六月香 | 怡红院最新网址 | 国模叶桐尿喷337p人体 | 久久成人网18网站 | 国产精品精品久久久 | 视频一区中文字幕 | 免费看a| 美女网站全黄 | 免费黄色激情视频 | 日韩激情综合网 | 韩国黄色av | 天天操天天干天天干 | 少妇献身老头系列 | 99国产精品久久 | 97成人资源 | 久久久久成人精品无码中文字幕 | 婷婷色在线播放 | 日韩精品 欧美 | 亚洲AV无码国产日韩久久 | 成人免费黄色小视频 | 小镇姑娘国语版在线观看免费 | 动漫同人高h啪啪爽文 | 超黄网站在线观看 | 亚洲一二三四五 | 日韩久久久久久久 | 日本一二三不卡视频 | 亚洲成人精品久久久 | a级片国产 | av影音先锋| 欧洲亚洲另类 | 午夜精品免费 | 亚洲天堂91 | 极品少妇xxxx精品少妇 | 久久免费国产 | 二级黄色片 | aa视频在线观看 | 91欧美精品| 欧美视频久久 | 日本少妇在线 | 伊人中文字幕 | 91偷拍网站 | 亚洲va在线| 六月婷婷av | 污污在线免费观看 | 国产欧美一级片 | 中文一区在线观看 | 五月天久久婷婷 | 巨胸挤奶视频www网站 | 91蜜桃视频在线观看 | 99国产精 | 亚洲国产影视 | 久一在线视频 | 国产精品色呦呦 | 精品熟女一区二区三区 | 99精品视频国产 | 国产精品2区| 日韩国产中文字幕 | 久久yy | 久色视频在线 | 久久免费黄色网址 | 国产av无码国产av毛片 | 欧洲人妻丰满av无码久久不卡 | 羞羞色视频| 91视频一区 | 美女被日网站 | 欧美日韩亚洲国产一区 | 国产午夜精品一区二区理论影院 | 精品1区2区3区 | 国产精品日日摸天天碰 | 成人动漫视频在线观看 | 国产对白羞辱绿帽vk |