你真的瞭解For循環嗎?一道For循環Java面試題引起的思考

疑問

最近羣友拋出了一個面試題,就是下圖中的第二題,是關於一個for循環的執行結果的問題,他的代碼的執行結果是什麼呢? java

代碼復現

下面的例子和麪試題上面的大同小異,是個很是簡單的例子。首先這個代碼是能夠編譯經過的,也能夠正常執行的。那麼執行結果是什麼呢?會跟咱們猜測的同樣嗎?git

/**
 * Created by baiguantao on 2017/10/20.
 */
public class T {
    public  static boolean  testA(char a){
        System.out.print(a);
        return true;

    }

    /**
     * for循環的一些疑問
     * @param args
     */
    public static void main(String[] args) {
        int i=0;
        for (testA('a');testA('b')&&(i<2);testA('c')) {
            i++;
            testA('d');
        }
    }
}
  • 執行結果

abdcbdcb面試

那麼問題來了,爲何是這個結果呢?咱們能夠藉助javap命令反編譯咱們剛纔編譯的T.class進行分析。 若是對jvm不瞭解的能夠參閱JVM基礎jvm

反編譯

  • 先貼出原版的字節碼反編譯後的代碼,後邊會對反編譯的文件進行逐行解析,那麼咱們先來看看上述類反編譯後的樣子吧。以下所示:
C:\Users\temp\IdeaProjects\mix_learn\target\classes>javap -c T.class
Compiled from "T.java"
public class T {
  public T();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static boolean testA(char);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: iload_0
       4: invokevirtual #3                  // Method java/io/PrintStream.print:(C)V
       7: iconst_1
       8: ireturn


  public static void main(java.lang.String[]);
    Code:
       0: iconst_0
       1: istore_1
       2: bipush        97
       4: invokestatic  #4                  // Method testA:(C)Z
       7: pop
       8: bipush        98
      10: invokestatic  #4                  // Method testA:(C)Z
      13: ifeq          39
      16: iload_1
      17: iconst_2
      18: if_icmpge     39
      21: iinc          1, 1
      24: bipush        100
      26: invokestatic  #4                  // Method testA:(C)Z
      29: pop
      30: bipush        99
      32: invokestatic  #4                  // Method testA:(C)Z
      35: pop
      36: goto          8
      39: return
}
  • 說明版本

對反編譯後的文件是否是一臉懵逼,沒太看懂是什麼意思呢?不要緊,下面咱們進行逐行分析。函數

C:\Users\temp\IdeaProjects\mix_learn\target\classes>javap -c T.class
Compiled from "T.java"
public class T {
  public T(); // 這裏是默認生成的無參構造函數部分開始
    Code:
       0: aload_0                           //表示對this的操做
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V   調用特殊實例方法
       4: return                            // 返回結果 
                    // 這裏是默認生成的無參構造函數部分結束
  public static boolean testA(char);// 這裏是咱們寫入的靜態方法
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;   System.out調用類方法
       3: iload_0                           //從局部變量表中加載int型的數據到操做數棧
       4: invokevirtual #3                  // Method java/io/PrintStream.print:(C)V  調用實例方法
       7: iconst_1                          //int類型0進棧 
       8: ireturn                           // 返回結果

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0                          //int類型0進棧 
       1: istore_1                          // int類型1出棧
       2: bipush        97                  // byte型常量97(a)進棧
       4: invokestatic  #4                  // Method testA:(C)Z  執行靜態方法testA
       7: pop                               // 棧頂數值出棧(不能是long/double)
       8: bipush        98                  // byte型常量98(b)進棧
      10: invokestatic  #4                  // Method testA:(C)Z  執行靜態方法testA
      13: ifeq          39                  //判斷語句  是否相等  循環結束 跳轉到39
      16: iload_1                           //從局部變量表中加載int型的數據到操做數棧
      17: iconst_2                          //int類型2進棧 
      18: if_icmpge     39                  //比較棧頂兩int型數值大小,當結果大於等於0時跳轉到39的位置 
      21: iinc          1, 1                //給局部變量表的1號位置的int值增長1
      24: bipush        100                 // byte型常量100(d)進棧 
      26: invokestatic  #4                  // Method testA:(C)Z  執行靜態方法testA
      29: pop                               // 棧頂數值出棧(不能是long/double)
      30: bipush        99                  // byte型常量99(c)進棧 
      32: invokestatic  #4                  // Method testA:(C)Z 執行靜態方法testA
      35: pop                               // 棧頂數值出棧(不能是long/double)
      36: goto          8                   // 從新循環 到8的位置
      39: return                            //退出循環
}
  • 流程圖

總體上的結構this

 

for循環執行流程spa

 

總結

從反編譯文件以及流程圖中咱們能夠看出for循環執行的順序是:.net

  • testA(a)
  • testA('b')
  • testA('d')
  • testA('c')
  • testA('b')
  • testA('d')
  • testA('c')
  • testA('b')

因此咱們的執行輸出結果是:abdcbdcbblog

最後

不對之處還望你們指正。ip

做者 ricky

交流羣:244930845

相關文章
相關標籤/搜索