為什么for循環中的a=a++,a總是0


老張大魔王 2018-03-19

作者 老張大魔王

今天朋友去面試,遇到了一個非常"簡單"的題目,如下

a = 0;

for(int i = 0; i < 10; i++) {

    a = a++;

}

System.out.println(a); //a = ?

  

 

 
         

 

當時老張就一臉懵逼的說,a不是等於10嗎??

朋友當時就說,培訓出來的都知道a最后等於0

此時老張陷入了深深的思索之中,按理說是a取值a=0,a++=1,然后a=a++,十次之后當然等於10啊,

於是老張打開IDE寫下如下代碼並運行:

 

class a{

    public static void main(String [] args) {

         int a=0;

         for (int i = 0; i < 10; i++) {

             a=a++;



         }

         System.out.println(a);

        }

}
 

 

javac a.java

java a.class

  

 

結果竟然真的是0,這個時候老張一度懷疑自己是個假程序員.

於是老張本着鑽牛角尖的精神,使用javap命令查看字節碼命令

 

 

javap -c a.class

 

得到如下代碼

 

 

Compiled from "a.java"

class a {

  a();

    Code:

       0: aload_0

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

       4: return

  public static void main(java.lang.String[]);

    Code:

       0: iconst_0

       1: istore_1

       2: iconst_0

       3: istore_2

       4: iload_2

       5: bipush        10

       7: if_icmpge     21

      10: iload_1

      11: iinc          1, 1

      14: istore_1

      15: iinc          2, 1

      18: goto          4

      21: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;

      24: iload_1

      25: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V

      28: return

}
 

 

一目了然,不過我們這樣看更簡單 

 

 

class a{

    public void test() {

        int a=0;

        a=a++;//a=0

    }

}

 

 

使用javap -c

Compiled from "a.java"

class a {

  a();

    Code:

       0: aload_0

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

       4: return

  public void test();

    Code:

       0: iconst_0            //a=0     //將int型的0推送至棧頂

       1: istore_1            //     //將int型的數值存入第二個本地變量

       2: iload_1             //     //將第二個int型本地變量推送至棧頂

       3: iinc          1, 1  //     //++操作  局部變量自增指令

       6: istore_1            //     //將int型的數值存入第二個本地變量

       7: return

}
Compiled from "a.java"

class a {

  a();

    Code:

       0: aload_0

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

       4: return

  public void test();

    Code:

       0: iconst_0            //a=0     //將int型的0推送至棧頂

       1: istore_1            //     //將int型的數值存入第二個本地變量

       2: iload_1             //     //將第二個int型本地變量推送至棧頂

       3: iinc          1, 1  //     //++操作  局部變量自增指令

       6: istore_1            //     //將int型的數值存入第二個本地變量

       7: return

}

 

 

 

 

class a{

    public void test() {

        int a=0;

        a=++a;    //a=1

    }

}

 

 

 

Compiled from "a.java"

class a {

  a();

    Code:

       0: aload_0

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

       4: return

  public void test();

    Code:

       0: iconst_0

       1: istore_1

       2: iinc          1, 1

       5: iload_1

       6: istore_1

       7: return

}

 

 

對比如下指令

 

a++

                                                                                                   

 

      0: iconst_0            //a=0     //將int型的0推送至棧頂

       1: istore_1            //    //將int型的數值存入第二個本地變量

       2: iload_1             //     //將第二個int型本地變量推送至棧頂

       3: iinc          1, 1  //     //++操作  局部變量自增指令

       6: istore_1            //     //將int型的數值存入第二個本地變量

       7: return    

 

++a

     

 

      0: iconst_0        //a=0    //將int型的0推送至棧頂

       1: istore_1         //    //將int型的數值存入第二個本地變量

       2: iinc          1, 1    //    //++操作  局部變量自增指令

       5: iload_1        //    //將第二個int型本地變量推送至棧頂

       6: istore_1        //    //將int型的數值存入第二個本地變量

       7: return

 

所有至關重要的異步就是:    iinc(局部變量自增)指令與iload_1指令的先后順序決定的a的值

 

 

那么問題又回到了,i++和++i先加后加的路子上,這句話好耳熟

 

詳細的說,現在我們一步步的分析下a=a++到底做了什么

1)inconst_0將0推送至棧頂

 

 

 

2)istore 將int型的數值存入第二個本地變量

 

 

 

3)iload_1 將第2個本地類型推送至棧頂

 

 

3)iinc    局部變量自增指令(注意是局部變量)

 

 

 

4)istore_1 將int型的值存入第二個局部變量表中(此時棧中的0將覆蓋局部變量表中的1)

 

 

所以a=a++之所以結果為0,應為局部變量自增的值被覆蓋了

所以a=++a的字節碼指令聰明的你肯定也懂了

 

再簡單的補充一下關於Java棧的一些知識

Java中棧是由棧幀組成,每個棧幀都是線程私有的.

每個棧幀包含4塊內容:

 

1)局部變量表

        局部變量表用來存儲參數局部變量,以slot為單位,除了long和double占2個slot,其余的6個基本類型和reference(引用)占1個slot

 

2)操作棧(操作數棧)

        操作棧成為"基於棧的執行引擎",方法執行中進行算術運算或者是調用其他的方法進行參數傳遞的時候是通過操作數棧進行的

 

3)動態鏈接

        略

 

4)返回地址

        略

 

我的公眾號:

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM