List当中for循环的踩坑
来源:互联网 发布:费米估算法怎么用? 编辑:程序博客网 时间:2024/05/17 22:01
其实,本身我倒是没有踩坑,只是在做项目的时候留意了一下,然后等项目完成之后,自己又倒腾了一下,才发现,原来这里也有我的认知盲区,所以,把我这一次的经历分享一下。
关于List和for循环的知识点我就不做讲解了,我想万能的谷歌百度总能告诉你很多。
先贴一下我在工作中的代码吧
好吧,这里可能要说明一下,虽然我在这里用了平行流,当然这个不是重点,重点在于datalist是一个List,然后后面的forEach就是一个for循环,然后里面的getOverdueAndPenlty方法就是对datalist当中每一个元素进行赋值操作。
本身倒也没有什么问题,后来我突然想到,在for循环里面对其中的元素进行操作,这样是不是可以。当然,以我的经验,对对象当中的元素的修改,这样肯定是没有问题的,但是项目紧急,也来不及我多想什么,想着早点做完早点再去想想吧。
好吧,然后一拖拖到了三天……哈哈哈(^__^)
今天在整理材料的时候发现了当初的这个设想,然后,很装逼地给自己冲了一杯咖啡。无咖啡,不Java。
一开始自己做了一个小Demo
class Stu { private int value; public Stu(int v){ this.value = v; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } @Override public String toString() { return "Stu [value=" + value + "]"; }}
public static void main(String[] args) { List<Stu> list = new ArrayList<>(); list.add(new Stu(1)); list.add(new Stu(2)); list.add(new Stu(3)); for(Stu stu : list){ stu.setValue(stu.getValue()+1); } for(Stu s : list){ System.out.println(s); }}
运行之后的结果:
看吧,说明对对象里面的值修改肯定是没什么问题的。那么我当时在考虑的是什么呢?
注意我说的话,对对象里面的值,而不是对象。
好吧,这话确实有点绕,那我再给你们演示一个Demo
public static void main(String[] args) { List<Stu> list = new ArrayList<>(); list.add(new Stu(1)); list.add(new Stu(2)); list.add(new Stu(3)); for(Stu stu : list){ stu = new Stu(stu.getValue() + 1); } for(Stu s : list){ System.out.println(s); }}
看上去好像也没什么不一样吧,但是结果还会一样吗?如图:
天哪‼️竟然没有变,我们不是明明修改了值吗?
好吧,这就是我当初感觉犹豫的地方。
那么就跟大家讲一下我的心路历程吧
我一开始考虑的时候,钻进了死胡同。我想的是,首先,list保存的是每一个变量的引用,也就是变量所处的堆栈的地址,然后这些堆栈各自指向堆当中的对象。如图:
好吧,这个手稿图画的还是蛮抽象的……(我自己都吐槽)
list当中保存的是stu1、stu2、stu3,然后各自对应着堆当中的1、2、3。其实这个图本身也没错,是这样的一回事情。然后我当时在想:
stu = new Stu(stu.getValue() + 1);
这个动作不就是让这个引用知道了其他的堆空间去了,list当中保存的栈依然没有变才是。但要是这样想,所以才钻了死胡同。
我甚至都在怀疑,上面这个赋值动作是否成功了,然后,就打印了一下,增加代码:
stu = new Stu(stu.getValue() + 1);System.out.println(stu);
结果:
对象确实改变了,这个是可以肯定的。
这个时候,我突然想到了一处地方。先不讲,我先把代码改动一下,给大家看看
public static void main(String[] args) { List<Stu> list = new ArrayList<>(); Stu stu1 = new Stu(1); Stu stu2 = new Stu(2); Stu stu3 = new Stu(3); list.add(stu1); list.add(stu2); list.add(stu3); for(Stu stu : list){ stu = new Stu(stu.getValue() + 1); System.out.println(stu); } for(Stu s : list){ System.out.println(s); } }
大家有没有发现,我把添加到list里面的对象,单独拎出来,为什么这样做,是因为我想看看,for循环当中遍历的变量是不是同一个,Debug一下,如图:
这下恍然大悟,原来不是同一个(注意他们的id值,大家可以把它当做是地址)。
所以,for循环当中的引用其实只是一个copy。这样说可能大家不会太懂,我还是继续给大家画图吧:
好吧,不要再让我画图了……
给大家讲一下吧,就是在for循环当中,其实是对list当中的东西的一个copy,因为stu1指向的是堆空间1,然后stu=stu1,一开始都是指向对空间1,就是图片当中的①。然后我们把一个新的对象赋给了stu,然后stu指向了堆空间④,这个时候stu的value确实是4,所以我们去打印这个值也是4,但是for循环结束之后,我们发现,在list当中的依旧只是stu1、stu2、stu3,他们所指向的堆空间依然没有什么变化,所以还是1、2、3。而那些新增的堆空间,就找不到了,因为没有记录起来。然后这也可以解释,最早之前的程序
stu.setValue(stu.getValue()+1);
这个动作,确确实实是对堆空间1、2、3进行了修改。
想到这里,就觉得一切都豁然开朗了,是的吧。
好吧,虽然只是开发过程中的一个小插曲,但是细细想来还是蛮有意思的,我觉得我可以把我的经历分享给大家,带给大家学习,当然,也希望可以的话,能打赏一些,这样我就有钱去买咖啡喝啦,哈哈哈……
- List当中for循环的踩坑
- 跳出Java当中的一些循环,跳出双层FOR循环
- js第二节-js当中for循环的应用
- List for循环与对象的问题
- list的遍历采用for循环。
- js当中数组和list遍历的时候,跳过本次循环执行下一次循环,以及跳出循环
- for循环的判断条件与内容的list重合,导致for循环一致进行
- List元素的几种for循环方式及其点评
- List元素的几种for循环方式及其点评
- C#中For循环和List.Find效率的比较
- for循环删除list中多个元素出现的误区
- Java中List for循环的6种写法
- for循环删除List中的数据产生的问题
- list、tuple和dict的for循环遍历
- Python用for循环来遍历list时,for循环体内有改动list长度的操作的情况
- java当中的List<E> 接口
- Javascript for 循环的坑
- 范围for 循环的坑
- HDOJ HDU 1029 Ignatius and the Princess IV
- AJAX与json php进行查询与新建
- Educational Codeforces Round 28 D. Monitor 二维rmq
- 垒骰子(经典递推、矩阵快速幂)
- Library Data Preparation for ICC---1
- List当中for循环的踩坑
- 网站字体的选择
- python基础语法学习记录之数据结构和算法(2)
- ServletJSP:上
- 538. Convert BST to Greater Tree
- Codeforces Round #430 (Div. 2)(A+B+C)
- iOS基础知识1
- 查验身份证(PAT-1031)
- kali升级之后theharvester不能使用