for和foreach forecah值引用

一.概念

for:

for循环是用下标索引,对数组或集合的元素进行确定的。

foreach:

1、foreach适用于数组或实现了iterator的集合类。foreach就是使用Iterator接口来实现对集合的遍历的。

2、在用foreach循环遍历一个集合时,不能使用集合自带的方法改变集合中的元素,如增加元素、删除元素。否则会抛出ConcurrentModificationException异常。也不能修改集合中的元素(不报异常),但可以修改元素的属性。

3、foreach是值传递,故对基本数据类型的修改只对形参起作用,对实参不起作.

二.示例

1.删除集合里的元素

(1)在for循环里,通过list.remove(索引)方法,移除list的元素--正常运行

List<String> list = new LinkedList<String>();
list.add("Guangzhou");
list.add("Shengzhen");
list.add("Beijing");
//for list.remocve(索引)--正常运行
for(int i=0;i<=list.size();i++){
    list.remove(0);
    i = 0;
}

(2)在for循环里,通过list.remove(值)方法,移除list的元素--正常运行 

 //for list.remove(值)--正常运行
for(int i=0;i<3;i++){
    System.out.println(list);
    if(list.get(1)=="Shengzhen")
    list.remove("Shengzhen");
}

(3)在foreach循环里,通过list.remove(索引)方法,移除list的元素--ConcurrentModificationException

报错的时间为,foreach循环第二次循环遍历时。

报错的地方为 for (String s:list) 该点。

原因是foreach底层是迭代器。

如果集合用迭代器进行遍历时,调用集合自身的list.remove(值),或者list.remove(索引)删除集合list自身的元素,第一次遍历过程中,调用remove方法会删除元素成功。

在第二次遍历时,迭代器会调用iterator.hasNext()方法,hasNext()是判断是否还有下一个元素。如果该集合有两个以上元素,则iterator.hasNext()会返回true,表示该集合接下来还有元素。然后会调用iterator.next()方法,来获取集合的下一个元素,此时iterator.next()内部会进行某些判断操作(篇幅较长下次再细说),然后iterator.next()返回ConcurrentModificationException。

        //foreach list.remove(值)--ConcurrentModificationException
        for (String s:list) {
            list.remove(s);
        }
        System.out.println(list);

在list集合数量只有两个时,不会报错。

在只有两个元素的时候,删除第一个元素后,只剩下一个,此时调用迭代器的hasNext()是为false,所以不会继续遍历。也不会继续调用迭代器的next()。因为list里面的第一个元素被删除了,所以第二个元素的索引就由1变成0,所以迭代器以为第二个元素已经被遍历获取过了,就不会再通过next()来获取它,从而显示它了。其实第二个元素并没有被遍历获取,只是由于第一个元素被删除,它变成了修改后数组的第一个元素。

如果集合list有三个元素,则hasNext()不会返回false,会返回true,接下来通过next()来获取list的第二个元素(即集合没删除之前的第三个元素),此时由于next()内部的判断机制(下次再仔细讲解),在调用list自身的remove方法删除元素的情况下,会ConcurrentModificationException异常。

        List<String> list = new LinkedList<String>();
        list.add("Guangzhou");
        list.add("Shengzhen");    

        for (String s:list) {
            System.out.println("foreach循环中的list 删除前:"+list);
            list.remove(s);
            System.out.println("foreach循环中的list 删除后:"+list);
        }
        System.out.println(list);    
foreach循环中的list 删除前:[Guangzhou, Shengzhen]
foreach循环中的list 删除后:[Shengzhen]
[Shengzhen]

(4)在foreach循环里,通过list.remove(值)方法,移除list的元素--ConcurrentModificationException

原因和上面👆通过list.remove(索引)方法移除list集合元素一样。

所以在集合只有两个元素的情况下,出现的情况也一样。

        //foreach list.remove(索引)--ConcurrentModificationException
        int i=0;
        for (String s:list) {
            list.remove(i);
        }    

2.修改集合里的元素

for循环是根据集合的索引来获取集合元素,从而对集合进行修改。

foreach是值传递,故如果实参是基本数据类型,则对形参的修改不会影响实参。如果实参是对象引用,则对形参的修改会影响实参。

(1)用foreach修改基本数据类型

 

        int[] arr = new int[10];
        System.out.println("foreach中增加的i");
        for(int i:arr){
            i++;
            System.out.println(i);
        }
        System.out.println("arr数组中i");
        for(int i:arr){
            System.out.println(i);
        }    

 

输出结果如下,可见foreach的实参是基本数据类型的情况下,值引用情况下赋值给形参的是,实参副本。对形参的修改,不会对实参造成影响。

foreach中增加的i
1
1
1
1
1
1
1
1
1
1
arr数组中i
0
0
0
0
0
0
0
0
0
0

(2)用foreach修改对象

class Per{
    Per(){
    }

    Per(String name,int age){
        this.name = name;
        this.age = age;
    }

    private String name;

    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}
public class TestForeach {
    public static void main(String[] args) {
        Per p1 = new Per("oneone",11);
        Per p2 = new Per("twotwo",12);
        Per p3 = new Per("threethree",13);

        List<Per> list = new LinkedList<Per>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        for (Per p:list) {
            p.setName("fourfour");
        }
        list.forEach(per -> {
            System.out.println(per.getName());
        });
    }
}

输出结果如下,可见foreach的实参是引用类型的情况下,值引用情况下赋值给形参的是,实参引用地址值的副本。对形参引用地址值所指向的对象的修改,会对实参引用地址值所指向的对象造成影响,因为这两个引用的地址值是一样的,指向同一个对象。

fourfour
fourfour
fourfour

 

参考的大佬文章:

https://blog.csdn.net/li_xunhuan/article/details/99075208

https://blog.csdn.net/qq_26545305/article/details/78485224

posted @ 2020-11-21 11:28  aczy  阅读(500)  评论(0编辑  收藏  举报