一个Java增强型for循环的易犯错误,你注意到了吗?

我们知道,在Java语言中有三种循环,分别是while循环,do…while循环和for循环。其实,从JDK1.5开始,又引入了一种增强型for循环,这种新型的for循环主要是用来遍历数组或集合的,它的格式非常简单,下图展示了增强型for循环的基本结构:


增强型for循环被设计出来就是为了遍历数组或者是集合的,所以在循环中都会指定一个数组或者是集合。为了方便程序员编码,增强型for循环不再通过”下标”的形式访问数组或集合中的元素,而是把依次从数组或集合取出元素,并命名为i,这样,程序员就可以直接操作元素i,从而大大简化了代码。为了方便表述,我们把元素i称之为“当前元素”。下面来看一个简单例子:

在这个增强型for循环中,指定的数组叫做array。每次循环,都从array数组中取出一个元素并命名为i,之后打印元素i的值。这里特意提醒各位小伙伴一下:循环中出现的”i”并非数组的下标,而是一个数组元素,也就是我们前面所说的”当前元素“。这段程序运行结果是”1 2 3 “。如果使用传统的for循环也能达到同样的效果,代码如下:

仅从以上两段代码的运行结果来看,似乎增强型for循环和传统for循环没有什么区别。但是,如果把以上两段代码稍作修改,运行结果就会迥然不同。我们把第一段代码改为如下形式:

为了表述方便,我们把第一段修改后的代码称之为”代码①”。之后,把原来的第二段代码修改为以下形式:

同理,我们把修改后的第二段代码称为”代码②”。”代码①”和”代码②”都是在它们原来的版本基础之上添加了一段循环修改数组元素值的操作。
但是,再次运行程序就会发现,”代码①”的运行结果仍然是”1 2 3 ”,而”代码②”的运行结果是”3 4 5 ”,也就是说”代码①”中修改数组元素值的操作并没有起作用。这是为什么呢?就是因为:”代码①”中所谓的”当前元素”i其实是一个作用域仅限于循环自身的局部变量,每次循环开始的时候都要重新定义这个变量,并且重新用数组元素对变量i进行赋值。i的值来源于数组元素,但i本质上并不是数组元素本身,它只是数组元素的副本,因此修改i并不能改变数组元素的值。在”代码①”的第一个循环中,修改的就是局部变量i的值,而并非数组元素本身的值。因此,在”代码①”的第二个循环中打印”当前元素”,实际上是再次把数组元素的值赋值给局部变量i并且打印,既然数组元素的值并未改变,打印出的结果当然是原数组中的”1 2 3”。
再来看”代码②”,”代码②”中的第一个循环是通过下标的直接找到了真实的数组元素并且做了修改,每次操作都修改的是实实在在的数组元素,而不是数组元素的副本!所以程序运行到第二个循环中,打印的是修改后的数组元素。
以上讲解,就是为了让小伙伴们明白:增强型for循环中的那个”当前元素i”,其实是一个临时的局部变量,它只是数组元素的副本,而非数组元素本身。但是,我们所举的例子中,数组的类型属于基础数据类型。那么,如果数组并非基础类型,而是引用类型,使用增强型for循环能否修改数组元素呢?请看以下代码:

在这段代码中,首先定义了一个Num类,在Num类中有一个int型的属性x,我们通过构造方法初始化x的值。代码的Test类中,在主方法里定义了一个Num类型的数组array,这个数组显然是一个引用类型数据的数组。数组中的引用分别指向了3个Num类型的对象,这三个对象的x属性值分别是1,2,3。第一个for循环修改了数组中每个Num对象的x属性值,第二个循环依次打印出每个Num对象的x属性值,程序运行结果是在控制台上输出了”3 4 5”。这说明增强型for循环在遍历引用类型的数组时,通过”当前元素”可以修改数组中元素的状态,这又是为什么呢?原因其实也很简单,虽然”当前元素”n本质上也只是一个作用域仅限于循环内部的局部引用,但是,每次循环过程中,它都实实在在的指向了一个真实的数组元素,所以这个局部引用作用域虽小,但通过它却能够完成修改数组元素对象属性值的操作。

另外再强调一点,无论增强型for循环所遍历的是基础数据类型的数组,还是引用类型的数组(或集合),都要保证”当前元素”与数组中真实元素的“类型兼容性”,否则程序就会报错。比如说,我们通过一个增强型for循环操作一个int型数组时,可以把”当前元素”i设定为double类型,原因就是数组中int型的元素可以赋值给double类型的局部变量。但反过来,通过增强型for循环操作一个double型数组时,不能把”当前元素”i的类型设定为int类型,就是因为按照Java语法,无法完成由double到int的自动转换。同理,操作一个String型数组时,可以把”当前元素”的类型设定为Object,反之则无法通过编译。

希望通过这篇文章能够让小伙伴们能更深入了解Java增强型for循环的本质。

如想系统学习Java编程,欢迎观看我在本站的视频课程。

原文地址:https://blog.51cto.com/2266836/2476240

时间: 2024-07-29 02:26:09

一个Java增强型for循环的易犯错误,你注意到了吗?的相关文章

编程中易犯错误汇总:一个综合案例.md

# 11编程中易犯错误汇总:一个综合案例 在上一篇文章中,我们学习了如何区分好的代码与坏的代码,如何写好代码.所谓光说不练假把式,在这篇文章中,我们就做一件事——一起来写代码.首先,我会先列出问题,然后要求读者自己写一份答案:然后,我会给出我写的代码:最后,我们还会以这个问题为例,讨论编程中常见的错误. ## 1 问题描述 在[这个](http://wiki.openhatch.org/index.php?title=Scrabble_challenge)页面中,有一道Python相关的练习题,

[golang 易犯错误] golang 局部变量初始化:=的陷阱

我们知道,golang中局部变量初始化方法(使用“:=”创建并赋值),让我们在使用变量时很方便.但是,这也是易犯错误的地方之一.特别是这个初始化符还支持多个变量同时初始化,更特别的是它还支持原有变量赋值和新变量创建并赋值同时进行!也就是说如果有部分变量不存在的而另外一些是已声明好的,用:=来初始化部分变量同样有效.这其实也没什么,更方便了嘛.但是,go的好多语句还支持局部前置语句,比如在if,for,switch等语句的初始化条件语句中.在这些地方,当你以为使用了原有变量的时候,实际上go已经为

Python 基础教程 和 易犯错误(文本处理)

一:基础教程 (1)文件I/O  非常类似于 c语言:IO在计算机中指Input/Output,也就是输入和输出.由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接口. spath="D:/download/baa.txt" f=open(spath,"w") # Opens file for writing.Creates this file doesn't exist. f.write(&

样式易犯错误

1,可使字和图标对其 .logo_right img{ margin-right:10px; vertical-align: middle; 如: 2,a标签样式 .nav a:link ,.nav a:visited{ color:rgb(255,255,255); font-size:20px; text-decoration:none; } .nav a:hover ,.nav a:active{ color:#C00; text-decoration:none; font-size:20

初始化赋值时a = b = 常数 的易犯错误

1 #include <stdio.h> 2 #include <stdlib.h> 3 int main() 4 { 5 int a,b; a=b=2; //成功 6 //int a = b = 2;失败 7 printf("%d %d",a,b); 8 system("pause"); 9 return 0; 10 } 新手注意直接初始化变量的 int a = b = 2这样的写法会导致编译失败. 如何能让这个语句正确呢,那就在前面声明好

Java开发者易犯错误Top10

摘要:在Java中,有些事物如果不了解的话,很容易就会用错,如数组转换为数组列表.元素删除.Hashtable和HashMap.ArrayList和LinkedList.Super和Sub构造函数等,如果这些对你来说是陌生的,你可以在本文中了解它们. 本文总结了Java开发者经常会犯的前十种错误列表. Top1. 数组转换为数组列表 将数组转换为数组列表,开发者经常会这样做: [java] view plaincopy List<String> list = Arrays.asList(arr

Python初学的易犯错误

当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂.这里列出了常见的的一些让你程序 crash 的运行时错误. 1)忘记在 if , elif , else , for , while , class ,def 声明末尾添加 :(导致 “SyntaxError :invalid syntax”) 该错误将发生在类似如下代码中: ? 1 2 if spam == 42     print('Hello!') 2)使用 = 而不是 ==(导致“SyntaxError: i

指针函数的++(极易犯错误)

#include<stdio.h> #include<stdlib.h> #include<string.h> //实现字符串的拷贝 int main11() { char a[]={"dajdjaskd"}; char b[267]; int i; for(i=0;a[i]!='\0';i++) { *(b+i)=*(a+i); } b[i]='\0';//这个很重要呢,一定要加,否则这个结果就是乱码 printf("b== %s\n&q

&lt;06&gt;变量使用前易犯错误总结+if语句介绍及基本格式+if-else语句及嵌套+if语句的高级用法+if语句的使用注意点+arc4random_uniform 函数导入一个头文件&lt;stdlib.h&gt;+

1)变量要初始化 -1 0  ,或者1 依据程序而定 ---------------------------------- if语句介绍及基本格式 分支语句结构 1)if 格式: if(表达式/常量/变量){ 语句块1; } 原理: 1)先计算小括号中的表达式的值 真(1) 会执行 大括号中的语句 假(0) 不会执行 大括号中的语句 2) switch 1 #include <stdio.h> 2 3 int main(int argc, const char * argv[]) { 4 5