1. 程式人生 > >從面試題i = i++; 瞭解java記憶體模型

從面試題i = i++; 瞭解java記憶體模型

先問大家一個問題:

    int i = 0;
    i = i ++;
    System.out.print(i);// 結果為 0
    int i = 0;
    int j = i ++;
    System.out.print(j);// 結果為 0
    System.out.print(i);// 結果為 1

首先該程式碼在C/C++平臺執行 結果是1 因為C/C++所有操作都是在記憶體中進行的,但是java有虛擬機器的概念,虛擬機器把記憶體分塊詳情見JAVA虛擬機器記憶體詳解, 虛擬機器執行時 i++ 只改變本地變量表的值 操作棧頂的值還是0 賦值時候 i 從棧頂取出 還是 0

JAVA虛擬機器棧描述的是JAVA執行的記憶體模型
每個幀棧都有區域性變量表和運算元棧,在虛擬機器眼裡如何執行上述程式碼呢?

    0:iconst_0
    1:istore_1
    2:iload_1
    3:iinc 1,1
    6:istore_1
    7:iload_1

0 -> 將int型別的0入棧 放置到操作棧頂部
1 -> 將運算元棧棧頂的值0彈出,儲存到區域性變量表 index (索引)值為1的位置。(區域性變量表也是從0開始的,0位置一般儲存當前例項的this引用,當然靜態方法例外,因為靜態方法是類方法而不是例項方法)
2 -> 將區域性變量表index 1位置的值的副本入棧。(這時區域性變量表index為1的值是0,運算元棧頂的值也是0)
3 -> iinc是對int型別的值進行自增操作,後面第一個數值1表示,區域性變量表的index值,說明要對此值執行iinc操作,第二個數值1表示要增加的數值。(這時區域性變量表index為1的值因為執行了自增操作變為1了,但是運算元棧中棧頂的值仍然是0)
6 -> 將運算元棧頂的值彈出(值0),放到區域性變量表index為1的位置(舊值:1,新值:0),覆蓋了上一步區域性變量表的計算結果。
7 -> 將區域性變量表index 1位置的值的副本入棧。(這時區域性變量表index為1的值是0,運算元棧頂的值也是0)

總結:從執行順序可以看到,這裡第1和第6執行了2次將0賦值給變數i的操作(=號賦值),i++操作是在這兩次操作之間執行的,自增操作是對區域性變量表中的值進行自增,而棧頂的值沒有發生變化,這裡需要注意的是儲存這個初始值的地方是運算元棧而不是區域性變量表,最後再將棧頂的值覆蓋到區域性變量表i所在的索引位置中去。

如果你理解了上面的 那麼下面的題

    int i = 0;
    i = i++ + i++;
    System.out.print(i) //是多少呢
i = 1 // 不解釋了 上面看懂深入理解一下吧