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

一,疑问

最近群友抛出了一个面试题,就是下图中的第二题,是关于一个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: returnpublic 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

原文发布于微信公众号 - 架构师小秘圈(seexmq)

原文发表时间:2017-11-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Linyb极客之路

Java开发者易犯错误Top10

Arrays.asList()将返回一个数组内部是私有静态类的ArrayList,这不是java.util.ArrayList类,java.util.Array...

1234
来自专栏cs

c++那些事儿5.0 模板

模板 是泛型编程的重点,在后面的STL中,模板的功能得到广泛运用。 在java中泛型,集合都有模板的身影,弄清模板可以让我们更加深入学习。 ---- 可讲的...

36212
来自专栏软件开发

JavaScript学习总结(一)——ECMAScript、BOM、DOM(核心、浏览器对象模型与文档对象模型)

一、JavaScript简介 JavaScript是一种解释执行的脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型,它遵循ECMAScript标准...

2437
来自专栏菩提树下的杨过

Flash/Flex学习笔记(8):ActionScript3.0中的面对对象

首先要习惯AS3.0的几个BT约定: 1.一个.as文件中,只能定义一个类 2.类名称必须与.as的文件名相同 3.类定义中必须要有package包声明 4.一...

1849
来自专栏菩提树下的杨过

java学习:文件读写

java中有好几种读写文件的方法,但是个人觉得最简单的还是FileInputStream、FileOutputStream类,示例代码: package jmy...

2267
来自专栏ml

初学Java之Pattern与Matcher类

import java.util.regex.*; public class Gxjun{ public static void main(St...

2927
来自专栏码匠的流水账

聊聊storm trident的state

storm-2.0.0/storm-client/src/jvm/org/apache/storm/trident/state/StateType.java

751
来自专栏杂烩

使用javascript让项目支持热插拔 原

    突然想起之前做过的一个小项目,项目虽小,需求却不小,要求解析特定格式的字符串,并且特定格式并非一成不变,想要一套系统能够支持解析多变的规则且更改规则时不...

1782
来自专栏一个会写诗的程序员的博客

Kotlin 简单优雅的高阶函数Kotlin 简单优雅的高阶函数《Kotlin极简教程》正式上架:1 . Kotlin 函数式编程: 函数的组合。一切皆是函数。2. 简单好用的 Kotlin 类型别名

函数代表一种关系 f 的蕴涵逻辑流。这种蕴涵逻辑流,其实就是映射(Mapping)。

1173
来自专栏Hongten

python开发_++i,i += 1的区分

这样的语法在上述编程语言中可以实现自增(减),在python中也支持这样的语法,不过在python中

1931

扫码关注云+社区

领取腾讯云代金券