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


声明:本文转载自https://my.oschina.net/lt0314/blog/1554809,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

疑问

最近群友抛出了一个面试题,就是下图中的第二题,是关于一个for循环的执行结果的问题,他的代码的执行结果是什么呢? 

代码复现

下面的例子和面试题上面的大同小异,是个非常简单的例子。首先这个代码是可以编译通过的,也可以正常执行的。那么执行结果是什么呢?会跟我们猜想的一样吗?

/**  * 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基础

反编译

  • 先贴出原版的字节码反编译后的代码,后边会对反编译的文件进行逐行解析,那么我们先来看看上述类反编译后的样子吧。如下所示:
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                            //退出循环 }
  • 流程图

整体上的结构 

for循环执行流程 

总结

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

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

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

最后

不对之处还望大家指正。

作者 ricky

交流群:244930845

本文发表于2017年10月23日 12:39
(c)注:本文转载自https://my.oschina.net/lt0314/blog/1554809,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2179 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1