about 1 results (0.01 seconds)

你真的了解for循环吗?一道for循环面试题引发的思考

by LauCyun Nov 23,2017 14:20:14 8,688 views

最近在某群看到一个面试题,就是下图中的第二题:

是关于一个for循环的执行结果的问题,他的代码的执行结果是什么呢? 

代码复现

public class Test {
    public static boolean foo(char a) {
        System.out.print(a);
        return true;
    }
    public static void main(String[] args) {
        int i = 0;
        for (foo('A'); foo('B') && (i < 2); foo('C')) {
            i++;
            foo('D');
        }
    }
}

这个代码是可以编译通过的,也可以正常执行的。那么执行结果是什么呢?

执行结果:

$ java Test
ABDCBDCB

那么问题来了,为什么是这个结果呢?我们可以借助javap命令反编译我们刚才编译的Test.class进行分析。

反编译

先贴出原版的字节码反编译后的代码,后边会对反编译的文件进行逐行解析,那么我们先来看看上述类反编译后的样子吧。如下所示:

$ javap -c Test.class
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static boolean foo(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        65
       4: invokestatic  #4                  // Method foo:(C)Z
       7: pop
       8: bipush        66
      10: invokestatic  #4                  // Method foo:(C)Z
      13: ifeq          39
      16: iload_1
      17: iconst_2
      18: if_icmpge     39
      21: iinc          1, 1
      24: bipush        68
      26: invokestatic  #4                  // Method foo:(C)Z
      29: pop
      30: bipush        67
      32: invokestatic  #4                  // Method foo:(C)Z
      35: pop
      36: goto          8
      39: return
}

对反编译后的文件是不是一脸懵逼,没太看懂是什么意思呢?没关系,下面我们进行逐行分析:

​$ javap -c Test.class
Compiled from "Test.java"
public class Test {
  public Test();  // 默认生成的无参构造函数部分开始
    Code:
       0: aload_0                           // 表示对this的操作
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V  // 调用特殊实例方法
       4: return                            // 返回结果 

  public static boolean foo(char); // 静态方法foo
    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类型1进栈 
       8: ireturn                           // 返回结果 

  public static void main(java.lang.String[]);
    Code:
       0: iconst_0                          // int类型0进栈 
       1: istore_1                          // int类型1出栈
       2: bipush        65                  // byte型常量65(A)进栈
       4: invokestatic  #4                  // Method foo:(C)Z   // 执行静态方法foo
       7: pop                               // 栈顶数值出栈(不能是long/double)
       8: bipush        66                  // byte型常量66(B)进栈
      10: invokestatic  #4                  // Method foo:(C)Z   // 执行静态方法foo
      13: ifeq          39                  // 判断语句,是否相等,循环结束就跳转到 Code 39
      16: iload_1                           // 从局部变量表中加载int型的数据到操作数栈
      17: iconst_2                          // int类型2进栈
      18: if_icmpge     39                  // 比较栈顶两int型数值大小,当结果大于等于0时跳转到 Code 39
      21: iinc          1, 1                // 给局部变量表的1号位置的int值增加1
      24: bipush        68                  // byte型常量68(D)进栈
      26: invokestatic  #4                  // Method foo:(C)Z   // 执行静态方法foo
      29: pop                               // 栈顶数值出栈(不能是long/double)
      30: bipush        67                  // byte型常量67(C)进栈
      32: invokestatic  #4                  // Method foo:(C)Z   // 执行静态方法foo
      35: pop                               // 栈顶数值出栈(不能是long/double)
      36: goto          8                   // 重新循环,回到 Code 8 的位置
      39: return                            // 退出循环
} 

根据上面代码逻辑,绘制了如下for循环执行流程:

从反编译文件以及流程图中我们可以看出for循环执行的顺序是:

foo('A')
foo('B')
foo('D')
foo('C')
foo('B')
foo('D')
foo('C')
foo('B')

所以我们的执行输出结果是:ABDCBDCB。

参考

...

Tags Read More..