中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

在Java中使用i++時需要注意哪些問題

發布時間:2020-12-07 15:10:03 來源:億速云 閱讀:187 作者:Leah 欄目:開發技術

本篇文章為大家展示了在Java中使用i++時需要注意哪些問題,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

字節碼

  • Java字節碼對于虛擬機,就好像匯編語言對于計算機,屬于基本執行指令。
  • 虛擬機的指令由一個字節長度的、代表著某種特定操作含義的數字(稱為操作碼,Opcode)以及跟隨其后的零至多個代表此操作所需參數(稱為操作數,Operands)而構成。由于Java虛擬機采用面向操作數棧而不是寄存器的結構,所以大多數的指令都不包含操作數,只有一個操作碼。

局部變量表

局部變量表:Local Variables,被稱之為局部變量數組或本地變量表

定義為一個數字數組,主要用于存儲方法參數和定義在方法體內的局部變量,這些數據類型包括各類基本數據類型、對象引用(reference),以及returnAddress類型。

由于局部變量表是建立在線程的棧上,是線程的私有數據,因此不存在數據安全問題。

局部變量表所需的容量大小是在編譯期確定下來的,并保存在方法的Code屬性的maximum local variables數據項中。在方法運行期間是不會改變局部變量表的大小的。

操作數棧

操作數棧:Operand Stack ,使用數組實現的。

每一個獨立的棧幀除了包含局部變量表以外,還包含一個后進先出(Last - In - First -Out)的 操作數棧,也可以稱之為 表達式棧(Expression Stack)

操作數棧,在方法執行過程中,根據字節碼指令,往棧中寫入數據或提取數據,即入棧(push)和 出棧(pop)

  • 某些字節碼指令將值壓入操作數棧,其余的字節碼指令將操作數取出棧。使用它們后再把結果壓入棧
  • 比如:執行復制、交換、求和等操作
  • 操作數棧,主要用于保存計算過程的中間結果,同時作為計算過程中變量臨時的存儲空間。
     

接下來就是本文的正式內容,首先,我們先給出兩個結論:

  • i++與++i在不同情況下可能會有不同的結論;
  • 實例變量/類變量的i++并不是一個原子性的操作。
     

首先我們看一下i++與++i的解析:

當i++或者++i沒有涉及到其他操作時,兩者是沒有區別的。

// i++
public void method1(){
 int i = 10;
 i++;
}
// ++i
public void method2(){
 int i = 10;
 ++i;
}

對應的字節碼指令操作為:

// method1
0 bipush 10 // 將10這個整數壓入操作數棧
2 istore_1	// 將操作數棧棧頂元素保存到局部變量表中索引為1處
3 iinc 1 by 1 // 局部變量表中索引為1處的元素,也就是i進行自增(這一步是在局部變量表上直接進行的,與操作數棧無關)
6 return // 方法返回

// method2
0 bipush 10
2 istore_1
3 iinc 1 by 1 // ++i
6 return

其中關于給出的具體字節碼細節以及棧幀中操作數棧、局部變量表在本文開頭給出了一些簡介,具體內容不展開描述,讀者可翻閱與之有關的資料。

通過反編譯可以看出,i++與++i的字節碼在沒有和其他操作組合時,字節碼是完全相同的。

當i++或者++i涉及到其他操作時,兩者的字節碼會有一些改變。

public void method7(){
  int i = 10;
  int a = i++;

  int j = 20;
  int b = ++j;
 }

對應的的字節碼指令:

 0 bipush 10
 2 istore_1	
 3 iload_1		// i++先從局部變量表中讀取i到操作數棧
 4 iinc 1 by 1	// i直接在局部變量表上進行自增
 7 istore_2		// 將操作數棧上讀取到的i的值賦值給a,也就是10
 8 bipush 20
10 istore_3
11 iinc 3 by 1	// ++j則先在局部變量表上進行自增
14 iload_3		// 再從局部變量表中讀取j到操作數棧
15 istore 4		// 將操作數棧上讀取到的j的值賦值給b,也就是21
17 returns

通過反編譯可以看出,i++與++i的字節碼在沒有和其他操作組合時,i++是先取值再自增,而++i是先自增再取值。

還有一個關于i=i++的解析:

public void method8(){
  int i = 10;
  i = i++;
  System.out.println(i);//10
 }

對應的字節碼指令:

 0 bipush 10
 2 istore_1
 3 iload_1		// 從局部變量表中讀取i到操作數棧
 4 iinc 1 by 1	// i直接在局部變量表上進行自增,此時i = 11
 7 istore_1		// 將之前操作數棧上讀取到的i的值賦值給i,之前自增的值被覆蓋了,i = 10
 8 getstatic #2 <java/lang/System.out>
11 iload_1
12 invokevirtual #5 <java/io/PrintStream.println>
15 return

然后看一下實例變量i++這行代碼的對應的字節碼

首先我們定義一個類

/**
 * @author XiaoLe
 * @create 2020-12-04 21:15
 * @description
 */
public class Test {
 private int i = 0;
 public void test(){
  i++;
 }
}

通過反編譯查看test方法中的字節碼:

 0 aload_0	
 1 dup
 2 getfield #2 <day001/Test.i> // 獲取到Test的i變量的值
 5 iconst_1	// 將int類型常量1壓入棧
 6 iadd	// 棧頂兩個元素相加后返回值入棧
 7 putfield #2 <day001/Test.i>
10 return

可以看到,i++這行代碼被拆分為三個字節碼,所以在一些并發情況下,i++如果不做同步處理,就可能會出現數據非一致性。

上述內容就是在Java中使用i++時需要注意哪些問題,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

拉萨市| 绥阳县| 潞西市| 南乐县| 黄大仙区| 鞍山市| 宜州市| 青州市| 嵊泗县| 呼和浩特市| 武平县| 玉龙| 亳州市| 左云县| 广元市| 临城县| 绥宁县| 育儿| 西昌市| 合阳县| 怀远县| 上饶市| 永川市| 炉霍县| 伊宁县| 海原县| 伊通| 探索| 文安县| 北川| 台江县| 东方市| 成安县| 宜兰县| 沙雅县| 三穗县| 苍梧县| 江都市| 阿勒泰市| 河池市| 屏东县|