Java中的"+"運算問題

恆222發表於2019-04-17

首先明確,筆者在這不討論"+"號作為字串拼接的作用,而是作為運算子產生的問題。
也就是說下在Java中 i+1 、 i++ 、 ++i之間的區別

含義

i+1

i++ 和 ++i 明顯區別於 i+1 的是前兩者的i的值都增加了。
如果給 i+1 賦值的話,又存在兩種情況:

  • i = i+1;
    這個過程的結果相當於 ++i,i 在這次運算中增加了一個數。
  • j = i+1;
    在這個運算裡 i 就相當於常量存在,自身不變。
    int x=0;
    int y=0;
    while(x<10){
        x = x+1;
        System.out.print(x+" ");
    }
    System.out.println();
    while(y<10){
        ++y;
        System.out.print(y+" ");
    }
複製程式碼

運算結果:

1 2 3 4 5 6 7 8 9 10 
1 2 3 4 5 6 7 8 9 10 
複製程式碼

在迴圈中來說,上面第一種情況的返回值的大小等價於 ++i ;第二種情況中 i 是不變的。

i++ 與 ++i

這兩者要放到一起討論。
通俗來講,其中 i++ 是先賦值後運算; ++i 是先運算後賦值,但他們在Java中都只能作為右值使用,不能作為左值。

左值是對應(refer to)記憶體中有確定儲存地址的物件的表示式的值,而右值是所有不是左值的表示式的值。
這兩個在迴圈中的程式碼:

int i = 0;
int j = 0;
while(i<6){
    int x = i++;
    System.out.print(x+""+i+" ");
}
System.out.println();
while(j<6){
    int y = ++j;
    System.out.print(y+""+j+" ");
}
複製程式碼

結果:

01 12 23 34 45 56 
11 22 33 44 55 66 
複製程式碼

他們在暫存器中的運算過程用程式碼表示如下:

i++ >>>
0: iconst_0               
1: istore_1               
2: iload_1                
3: iinc          1, 1     
6: istore_2  
7: return

++i >>>
0: iconst_0               
1: istore_1                
2: iinc          1, 1      
5: iload_1                 
6: istore_2      
7: return 
複製程式碼

也就是說i++ 運算中,棧頂值是 0 ,++i 運算中棧頂值是 1。

總的來說,在 i++ 與 ++i 這兩個運算中i都是增加了的,只是 i++ 返回的值是增加前的值, ++i 返回的值是增加後的值

使用中的注意事項

1. 有一個騷操作 i = i++; while迴圈中出現這個基本就死迴圈了

int i = 0;
while (i < 2) {
    i = i++;
    System.out.println(i);
}
複製程式碼

結果就是一堆 0,你可以自己想想是為什麼。
對了如果你的輸出語句不換行控制檯是列印不出訊息的,因為結果長度超出限制了。

2.多執行緒中的併發問題

i++ 與 ++i 都並非執行緒安全的運算,因為這兩者都不是原子操作。

到這有人可能會想,是否可以用volatile關鍵字修飾來保證執行緒安全呢?答案是不能。因為volatile只能保證可見性,不能保證原子性。
那麼到底怎麼在多執行緒中保證這兩者的執行緒安全呢?有兩個辦法:

  1. 用java.util.concurrent.atomic.AtomicInteger原子類下面的方法來替換這兩個操作,當然這是整形的原子類,其他基本型別也有各自的原子類。這些原子類能保證原子操作。
  2. 同步塊。加鎖synchronized或者使用排他鎖。

ok,到此結束

相關文章