算是温习吧。问题比较基础,但是也比较重要。(虽然是C,但是很经典)

for循环可以说在每个程序中都少不了的,语句头包括三个部分:初始化,判读条件,一个表达式。

但是这三个部分的执行顺序是什么,这是我们所关心的,也是本文所要讨论的。

下面先看一段简单的代码。

[cpp] view plaincopy

 
  1. #include <stdio.h>
  2. int main()
  3. {
  4. int x, a;
  5. for (x=0,a=0; a<=1 && !x++; a++)
  6. {
  7. a++;
  8. }
  9. printf("%d", a);
  10. return 0;
  11. }

代码很简单,可是打印结果呢?

有的朋友可能会想当然的认为,  打印结果是1.

可是,真的是1吗?   复制到编译器上跑跑,奇迹般的发现,其实是2.

下面就分析下这简单代码。

第一步:初始化定义,x = 0, a = 0;

第二步:a小于1, x 的非为1,符合循环条件

第三步:x++后x自增为1.

第四步:进入循环体,a++,a自增为1.

第五步:执行循环语句头中的a++,a自增为2.

第六步:执行循环语句头的判读条件,a=2>1,故不满足,不执行循环语句。

第七步:打印a的值为2.

怎么样,现在豁然开朗了吧。(如果还是不懂...那就抱歉了。)

从这个例子,我们可以得出如下结论:

执行顺序是:初始化--判断--函数体——然后for循环的第3句--判断——函数体---for循环的第三句--判断……

下面解答几点疑惑:

1、第一次例如初始化i=0,是否还执行后面的i++或++i?

第一次先初始化,然后判断,i++就不执行了

2、第一次完了以后,初始化这句就不用了,是先执行i++还是限制性判断语句呢?

先执行i++

3、现在知道是先执行i++,再执行判断语句,i++不是后++吗,例如i为1,那i++后执行判断语句,i是几呢?

i是2.

4、好像i++和++i在for()里时结果都一样。

都一样,for语句头的执行顺序决定了这两个写法都一样,都是i++或这++i这两句执行完了再进行判断,此时(两种情况)i已经加1了。

分析了这么多,相信大家也都懂了。

留个经典的例子,让大家自己去分析吧。

[cpp] view
plain
copy

 
  1. #include <stdio.h>
  2. int main( )
  3. {
  4. int i = 0, j = 10;
  5. for(i=0; i<j; i++,j--)
  6. {
  7. if(j==10)
  8. {
  9. printf("%d,%d ",i,j);
  10. j--;
  11. }
  12. j++;
  13. }
  14. printf("%d,%d ",i,j);
  15. return 0;
  16. }

打印结果:

0,10 9,9 

如果不懂的,可以参照下面这个对上述例子逐句打印的例子,应该会有助于理解。

[cpp] view
plain
copy

 
  1. #include <stdio.h>
  2. int print1(int i,int j)
  3. {
  4. printf("执行判断条件,i=%d,j=%d \n",i,j);
  5. return 1;
  6. }
  7. int main( )
  8. {
  9. int i = 0, j = 10;
  10. for(i=0;((print1(i,j)) && (i<j));
  11. i++,j--,printf("执行for()中的第三个语句,i=%d,j=%d \n",i,j))
  12. {
  13. if(j==10)
  14. {
  15. printf("%d,%d ",i,j);
  16. j--;
  17. }
  18. j++;
  19. printf("执行for循环体中的最后一句,i=%d,j=%d\n ",i,j);
  20. }
  21. printf(" %d,%d ",i,j);
  22. return 0;
  23. }

打印结果:

执行判断条件,i=0,j=10 

0,10 执行for循环体中的最后一句,i=0,j=10

 执行for()中的第三个语句,i=1,j=9 

执行判断条件,i=1,j=9 

执行for循环体中的最后一句,i=1,j=10

 执行for()中的第三个语句,i=2,j=9 

执行判断条件,i=2,j=9 

执行for循环体中的最后一句,i=2,j=10

 执行for()中的第三个语句,i=3,j=9 

执行判断条件,i=3,j=9 

执行for循环体中的最后一句,i=3,j=10

 执行for()中的第三个语句,i=4,j=9 

执行判断条件,i=4,j=9 

执行for循环体中的最后一句,i=4,j=10

 执行for()中的第三个语句,i=5,j=9 

执行判断条件,i=5,j=9 

执行for循环体中的最后一句,i=5,j=10

 执行for()中的第三个语句,i=6,j=9 

执行判断条件,i=6,j=9 

执行for循环体中的最后一句,i=6,j=10

 执行for()中的第三个语句,i=7,j=9 

执行判断条件,i=7,j=9 

执行for循环体中的最后一句,i=7,j=10

 执行for()中的第三个语句,i=8,j=9 

执行判断条件,i=8,j=9 

执行for循环体中的最后一句,i=8,j=10

 执行for()中的第三个语句,i=9,j=9 

执行判断条件,i=9,j=9 

 9,9 

下面讲述for循环在遍历过程中的使用

J2SE 1.5提供了另一种形式的for循环。借助这种形式的for循环,可以用更简单地方式来遍历数组和Collection等类型的对象。本文介绍使用这种循环的具体方式,说明如何自行定义能被这样遍历的类,并解释和这一机制的一些常见问题。

在Java程序中,要“逐一处理”――或者说,“遍历”――某一个数组或Collection中的元素的时候,一般会使用一个for循环来实现(当然,用其它种类的循环也不是不可以,只是不知道是因为for这个词的长度比较短,还是因为for这个词的含义和这种操作比较配,在这种时候for循环比其它循环常用得多)。

对于遍历数组,这个循环一般是采取这样的写法:

清单1:遍历数组的传统方式

/* 建立一个数组 */

int[] integers = {1, 2, 3, 4};

/* 开始遍历 */

for (int j = 0; j<integers.length; j++){

int i = integers[j];

System.out.println(i);

}

而对于遍历Collection对象,这个循环则通常是采用这样的形式

清单2:遍历Collection对象的传统方式

/* 建立一个Collection */

String[] strings = {"A", "B", "C", "D"};

Collection stringList = java.util.Arrays.asList(strings);

/* 开始遍历 */

for (Iterator itr = stringList.iterator(); itr.hasNext();) {

Object str = itr.next();

System.out.println(str);

}

而在Java语言的最新版本――J2SE 1.5中,引入了另一种形式的for循环。借助这种形式的for循环,现在可以用一种更简单地方式来进行遍历的工作。

1. 第二种for循环

不严格的说,Java的第二种for循环基本是这样的格式:

for (循环变量类型 循环变量名称 : 要被遍历的对象) 循环体

借助这种语法,遍历一个数组的操作就可以采取这样的写法:

清单3:遍历数组的简单方式

/* 建立一个数组 */

int[] integers = {1, 2, 3, 4};

/* 开始遍历 */

for (int i : integers) {

System.out.println(i);/* 依次输出“1”、“2”、“3”、“4” */

}

这里所用的for循环,会在编译期间被看成是这样的形式:

清单4:遍历数组的简单方式的等价代码

/* 建立一个数组 */

int[] integers = {1, 2, 3, 4};

/* 开始遍历 */

for (int 变量名甲 = 0; 变量名甲<integers.length; 变量名甲++)="" {

System.out.println(integers[变量名甲]);/* 依次输出“1”、“2”、“3”、“4” */

}

这里的“变量名甲”是一个由编译器自动生成的不会造成混乱的名字。

而遍历一个Collection的操作也就可以采用这样的写法:

清单5:遍历Collection的简单方式

/* 建立一个Collection */

String[] strings = {"A", "B", "C", "D"};

Collection list = java.util.Arrays.asList(strings);

/* 开始遍历 */

for (Object str : list) {

System.out.println(str);/* 依次输出“A”、“B”、“C”、“D” */

}

这里所用的for循环,则会在编译期间被看成是这样的形式:

清单6:遍历Collection的简单方式的等价代码

/* 建立一个Collection */

String[] strings = {"A", "B", "C", "D"};

Collection stringList = java.util.Arrays.asList(strings);

/* 开始遍历 */

for (Iterator 变量名乙 = list.iterator(); 变量名乙.hasNext();) {

Object str = 变量名乙.next();

System.out.println(str);/* 依次输出“A”、“B”、“C”、“D” */

}

这里的“变量名乙”也是一个由编译器自动生成的不会造成混乱的名字。

因为在编译期间,J2SE 1.5的编译器会把这种形式的for循环,看成是对应的传统形式,所以不必担心出现性能方面的问题。

不用“foreach”和“in”的原因

Java采用“for”(而不是意义更明确的“foreach”)来引导这种一般被叫做“for-each循环”的循环,并使用“:”(而不是意义更明确的“in”)来分割循环变量名称和要被遍历的对象。这样作的主要原因,是为了避免因为引入新的关键字,造成兼容性方面的问题――在Java语言中,不允许把关键字当作变量名来使用,虽然使用“foreach”这名字的情况并不是非常多,但是“in”却是一个经常用来表示输入流的名字(例如java.lang.System类里,就有一个名字叫做“in”的static属性,表示“标准输入流”)。

的确可以通过巧妙的设计语法,让关键字只在特定的上下文中有特殊的含义,来允许它们也作为普通的标识符来使用。不过这种会使语法变复杂的策略,并没有得到广泛的采用。

“for-each循环”的悠久历史

“for-each循环”并不是一个最近才出现的控制结构。在1979正式发布的Bourne shell(第一个成熟的UNIX命令解释器)里就已经包含了这种控制结构(循环用“for”和“in”来引导,循环体则用“do”和“done”来标识)。

2. 防止在循环体里修改循环变量

在默认情况下,编译器是允许在第二种for循环的循环体里,对循环变量重新赋值的。不过,因为这种做法对循环体外面的情况丝毫没有影响,又容易造成理解代码时的困难,所以一般并不推荐使用。

Java提供了一种机制,可以在编译期间就把这样的操作封杀。具体的方法,是在循环变量类型前面加上一个“final”修饰符。这样一来,在循环体里对循环变量进行赋值,就会导致一个编译错误。借助这一机制,就可以有效的杜绝有意或无意的进行“在循环体里修改循环变量”的操作了。

清单7:禁止重新赋值

int[] integers = {1, 2, 3, 4};

for (final int i : integers) {

i = i / 2; /* 编译时出错 */

}

注意,这只是禁止了对循环变量进行重新赋值。给循环变量的属性赋值,或者调用能让循环变量的内容变化的方法,是不被禁止的。

清单8:允许修改状态

Random[] randoms = new Random[]{new Random(1), new Random(2), new Random(3)};

for (final Random r : randoms) {

r.setSeed(4);/* 将所有Random对象设成使用相同的种子 */

System.out.println(r.nextLong());/* 种子相同,第一个结果也相同 */

}

3. 类型相容问题

为了保证循环变量能在每次循环开始的时候,都被安全的赋值,J2SE 1.5对循环变量的类型有一定的限制。这些限制之下,循环变量的类型可以有这样一些选择:

循环变量的类型可以和要被遍历的对象中的元素的类型相同。例如,用int型的循环变量来遍历一个int[]型的数组,用Object型的循环变量来遍历一个Collection等

清单9:使用和要被遍历的数组中的元素相同类型的循环变量

int[] integers = {1, 2, 3, 4};

for (int i : integers) {

System.out.println(i);/* 依次输出“1”、“2”、“3”、“4” */

}

清单10:使用和要被遍历的Collection中的元素相同类型的循环变量

Collection< String> strings = new ArrayList< String>();

strings.add("A");

strings.add("B");

strings.add("C");

strings.add("D");

for (String str : integers) {

System.out.println(str);/* 依次输出“A”、“B”、“C”、“D” */

}

循环变量的类型可以是要被遍历的对象中的元素的上级类型。例如,用int型的循环变量来遍历一个byte[]型的数组,用Object型的循环变量来遍历一个Collection< String>(全部元素都是String的Collection)等。

清单11:使用要被遍历的对象中的元素的上级类型的循环变量

String[] strings = {"A", "B", "C", "D"};

Collection< String> list = java.util.Arrays.asList(strings);

for (Object str : list) {

System.out.println(str);/* 依次输出“A”、“B”、“C”、“D” */

}

循环变量的类型可以和要被遍历的对象中的元素的类型之间存在能自动转换的关系。J2SE 1.5中包含了“Autoboxing/Auto-Unboxing”的机制,允许编译器在必要的时候,自动在基本类型和它们的包裹类(Wrapper Classes)之间进行转换。因此,用Integer型的循环变量来遍历一个int[]型的数组,或者用byte型的循环变量来遍历一个Collection< Byte>,也是可行的。

清单12:使用能和要被遍历的对象中的元素的类型自动转换的类型的循环变量

int[] integers = {1, 2, 3, 4};

for (Integer i : integers) {

System.out.println(i);/* 依次输出“1”、“2”、“3”、“4” */

}

注意,这里说的“元素的类型”,是由要被遍历的对象的决定的――如果它是一个Object[]型的数组,那么元素的类型就是Object,即使里面装的都是String对象也是如此。

可以限定元素类型的Collection

截至到J2SE 1.4为止,始终无法在Java程序里限定Collection中所能保存的对象的类型――它们全部被看成是最一般的Object对象。一直到J2SE 1.5中,引入了“泛型(Generics)”机制之后,这个问题才得到了解决。现在可以用Collection< T>来表示全部元素类型都是T的Collection。

(转)java for循环的执行顺序和几种常用写法的更多相关文章

  1. for循环的执行顺序

    一边回顾基础一边记录记录做个整理,这篇关于for循环的执行顺序: for(表达式1;表达式2;表达式3) {循环体} 第一步,先对表达式1赋初值; 第二步,判别表达式2是否满足给定条件,若其值为真,满 ...

  2. Java Object 构造方法的执行顺序

    Java Object 构造方法的执行顺序 @author ixenos 为了使用类而做的准备工作包括三个步骤 1)加载:类加载器查找字节码(一般在classpath中找),从字节码创建一个Class ...

  3. [转载]for循环的执行顺序

    原文地址:for循环的执行顺序作者:想飞上天的美人鱼   for循环的执行顺序用如下表达式: for(expression1;expression2;expression3) { expression ...

  4. Java多线程之控制执行顺序

    概念: 多线程在并发环境中的正常执行顺序是随机无序的,并不能按照期盼的结果输出. 因为启动一个线程时,线程并不会立即执行,而是等待CPU的资源调度,CPU能调度哪个线程,是通过多种复杂的算法计算而来. ...

  5. java中静态代码执行顺序

    1.Java中静态变量只能在类主体中定义,不能在方法中定义. 静态变量属于类所有而不属于方法. 2. 静态块:用static申明,JVM加载类时执行,仅执行一次 构造块:类中直接用{}定义,每一次创建 ...

  6. 夯实Java基础系列7:一文读懂Java 代码块和执行顺序

    目录 Java中的构造方法 构造方法简介 构造方法实例 例 1 例 2 Java中的几种构造方法详解 普通构造方法 默认构造方法 重载构造方法 java子类构造方法调用父类构造方法 Java中的代码块 ...

  7. 夯实Java基础系列7:Java 代码块和执行顺序

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  8. C/C++语言for循环语句执行顺序

    for循环如下: ; i<; ++i) { } 执行顺序如下: 1.i=0  初始化初值 2.i<10 进行判断,如果条件为真,则继续执行 3.执行循环体代码 4.i++ 变量i自增 5. ...

  9. java 方法参数的执行顺序

    java方法的参数的执行顺序是从左到右还是从右到左呢? 写出一下测试程序: 1 import java.util.*; 2 import java.io.*; 3 public class Test ...

随机推荐

  1. 用Backtrack进行渗透测试评估

    Web应用程序的分析在渗透测试和漏洞评估中发挥了重要的作用.确定Web应用程序的正确信息(例如使用的插件,CMS类型等)都可以帮助测试者使用准确的漏洞来测试,能够降低整个渗透测试漏洞评估所花费的时间. ...

  2. vue-router单页应用简单示例(二)

    我们先来理一下思路. 图1:main.js 引入vue,App.vue,router/index.js文件 声明要渲染的Id为app,将App.vue中的模版渲染到入口界面(就是打开localhost ...

  3. eclipse下启动tomcat项目,访问tomcat默认端口显示404错误

    解决:打开eclipse的server视图,双击你配置的那个tomcat,打开编辑窗口,查看server locations,看看是否选择了第一个选项(默认是第一个选项),即use workspace ...

  4. Idea 常用功能汇总,工作中常用技巧

    1.隐藏没用到的文件 比如 IDEA 的项目配置文件(.iml 和.idea),打开 Settings-File Types, 加入要隐藏的文件后缀.  2.常用技巧 2.1 通过Alt+F8查看变量 ...

  5. ionic+AnjularJs实现省市县三级联动效果

    建议对ionic和AnjularJs有一定了解的人可以用到,很多时候我们要用到选择省份.城市.区县的功能,现在就跟着我来实现这个功能吧,用很少的代码(我这里是根据客户的要求,只显示想要显示的部分省份和 ...

  6. JS添加类似C# string.Format方法

    String.prototype.format=function()   {     if(arguments.length==0) return this;     for(var s=this, ...

  7. React Native 仿天猫物流跟踪时间轴

    最近心血来潮开始学习ReactNative,正好最近有一个项目可能会用到时间轴,页面原型类似于天猫的物流跟踪,如下图 分析之后决定使用ListView来实现,左边的时间轴则使用Art来绘制. 分析左边 ...

  8. php获取当天的开始时间和结束时间戳

    $begin_time=date("Y-m-d H:i:s",mktime(0,0,0,date('m'),date('d'),date('Y')));$over_time=dat ...

  9. Sublime text3插件安装方法

    一.安装sublime text3插件的方法: 1.Ctrl+~键,调出console,将下面代码复制到底部命令行,回车: import urllib.request,os; pf = 'Packag ...

  10. 打包可执行的jar

    #配置项目路径 *除程序文件以外,其他相关素材也可以打包进jar,但在内部访问时需以包名作为跟路径,如hello/xxx/yyy.zzz mkdir hello vi hello/HelloWorld ...