Java的增强for循环修改数组元素的问题小结
作者:Violet_Stray
曾经没怎么多想过for each有什么特殊的地方,以为就是for循环的简便写法,直到今天写力扣发现了不对劲,使用for each就是过不了,而用正规for循环就过了,决定来好好了解一下for each。
而有时候写增强for循环又可以修改属性
最后发现,是否能理解for each的修改与是否理解Java是值传递有很大的关系。
(完整代码放在最后)
决定从基本数据类型和引用数据类型两种类型来看。
首先简单看一下for each的遍历:
自定义了一个Person类,有name(String)和age(int)两个属性。
用int数组代表基本数据类型的数组,用String类和Person类代表引用数据类型的数组
输出结果都放在了注释里面:
public class Main { public static void main(String[] args) { // 1.能成功遍历基本数据类型的数组元素 int[] nums = { 1, 2, 3, 4, 5 }; for (int i : nums) { System.out.print(i + "\t"); } // 输出:1 2 3 4 5 System.out.println(); // 2.能成功遍历引用数据类型的数组元素 String[] strs = { "acd", "qwe", "oiu" }; for (String string : strs) { System.out.print(string + "\t"); } // 输出:acd qwe oiu System.out.println(); Person[] persons = { new Person("张三", 12), new Person("李四", 33), new Person("王五", 90) }; for (Person person : persons) { System.out.print(person + "\t"); } // 输出:Person [name=张三, age=12] Person [name=李四, age=33] Person [name=王五, age=90] System.out.println("-----------------------------------------------------------"); } class Person { String name; int age; public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = 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; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
再来看看使用for each来修改数据:(和上面代码重复的内容不再写)
public class Main { public static void main(String[] args) { //这些数据没有变 int[] nums = { 1, 2, 3, 4, 5 }; String[] strs = { "acd", "qwe", "oiu" }; Person[] persons = { new Person("张三", 12), new Person("李四", 33), new Person("王五", 90) }; // 3.修改基本数据类型的数组元素的值 for (int i : nums) { if (i == 4) { i = 233; System.out.println("已修改"); } } for (int i : nums) { System.out.print(i + "\t"); } // 输出:1 2 3 4 5 // 说明nums数组并未修改 System.out.println(); // 4.修改引用数据类型的数组元素的值 for (String string : strs) { if (string.equals("acd")) { string = "hello world"; System.out.println("已修改"); } } for (String string : strs) { System.out.print(string + "\t"); } // 输出:acd qwe oiu // 说明str数组并未修改 System.out.println(); for (Person person : persons) { if (person.name.equals("张三")) { person.age = 100; System.out.println("已修改"); } } for (Person person : persons) { System.out.print(person + "\t"); } // 输出:Person [name=张三,age=100] Person [name=李四,age=33] Person [name=王五,age=90] // 说明persons数组有修改 System.out.println(); } }
结果:int数组和String数组多没能成功修改,而只有Person数组成功修改了
为什么Person数组能修改成功呢?因为Java是值传递。能理解这个非常重要!
(理解的朋友可以跳过下面这一段)
理解Java是值传递:
首先什么是值传递,什么是引用传递呢?
- 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
- 引用传递是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
主要区别就在于是否将实际参数复制
那为什么说Java是值传递呢?按照这么说,Java其实是将实际参数复制过传递到函数中的呀!
有人举例说把int等基本数据类型作为参数,并不能修改实参的值,能说明Java是值传递,而传递Person这种自定义的类,在函数中修改属性之后,在主函数中调用却能成功修改,这并不能说明Java是值传递,反而像引用传递呀?
曾经看到一个例子:
- 你的朋友借给你一把钥匙,你朋友就相当于主函数,你相当于主函数中调用的另一个函数,钥匙就是实参,你这个函数就相当于进入朋友家中,干一些事情之后离开。你拿着这把钥匙,能打开他们家的大门,于是你进了他们家,砸坏了他们家的电视机(相当于修改Person类的属性)。当这个函数结束的时候,就相当于你已经离开了你朋友的家中。你朋友拿着钥匙打开了自家的门,发现电视机被砸坏了(相当于你在输出端看到在主属性Print的Person的属性值被修改了),
于是朋友把你揍了一顿。
所以说在子函数中修改属性,这个属性并非是传递进来的参数。传递进来的参数是钥匙!而不是会被砸的电视机!
Java是值传递可以理解为,你拿着你朋友家的钥匙又复刻了一把,所以现在有两把钥匙。你和你朋友都能用两把钥匙打开朋友家的门!
意思就是有两个引用同时指向了同一个地址,第二个复制的引用正是子函数中的局部变量。无论是用哪一个引用对属性修改,都能直接在内存中修改,于是会出现传递Person类修改属性会看到成功修改的结果。
如何体现值传递的特征呢——修改传递过来的值,并不会影响原来的对象:
就好比,你在复刻的钥匙上写下自己的名字,你朋友的钥匙上并不会出现你的名字。
就意味着你用子函数中的引用去指向一个新对象,而主函数中的引用并不会去指向那个新对象一样,还是指向原来的对象。
所以说Java是值传递,而并发引用传递!
回到增强for循环:
for(元素类型t 元素变量x : 遍历对象obj){ 引用了x的java语句; }
增强for循环的元素变量x,就是一个局部变量,它是引用数组当前元素引用的副本(就相当于上文所说的你复刻朋友的钥匙),或者是基本数据类型的值的副本。
可以这么理解:
int[] nums = { 1, 2, 3, 4, 5 }; for (int i : nums) { if (i == 4) { i = 233; } } //相当于: for(int j=0;j<nums.length;j++){ int i=nums[j]; if(i==4){ i=233; } //所以说修改对于原数组根本没有任何影响 }
对于String数组相当于:
for (int j = 0; j < strs.length; j++) { String i = strs[j]; if (i.equals("acd")) { i = "hello world"; } } //String类是不可变对象,所以这里也没有任何影响 //输出:acd qwe oiu
对于Person类相当于:
for(int j=0;j<persons.length;j++) { Person i=persons[j]; if (i.name.equals("张三")) { i.age = 100; //这里改变的是persons[j].age,而不是persons[j]本身,所以能成功改变 } }
如果是这样:
for (int j = 0; j < persons.length; j++) { Person i = persons[j]; if (i.name.equals("李四")) { i = new Person("A", 80); //i指向一个新对象,输出结果也毫无变化,不会输出(A,80) } }
总而言之:如果想要修改元素就用正规for循环,不要使用增强for循环。
所有的代码:
public class Main { public static void main(String[] args) { // 1.能成功遍历基本数据类型的数组元素 int[] nums = { 1, 2, 3, 4, 5 }; for (int i : nums) { System.out.print(i + "\t"); } // 输出:1 2 3 4 5 System.out.println(); // 2.能成功遍历引用数据类型的数组元素 String[] strs = { "acd", "qwe", "oiu" }; for (String string : strs) { System.out.print(string + "\t"); } // 输出:acd qwe oiu System.out.println(); Person[] persons = { new Person("张三", 12), new Person("李四", 33), new Person("王五", 90) }; for (Person person : persons) { System.out.print(person + "\t"); } // 输出:Person [name=张三, age=12] Person [name=李四, age=33] Person [name=王五, age=90] System.out.println(); System.out.println("-----------------------------------------------------------"); // 3.修改基本数据类型的数组元素的值 for (int i : nums) { if (i == 4) { i = 233; System.out.println("已修改"); } } for (int i : nums) { System.out.print(i + "\t"); } // 输出:1 2 3 4 5 // 说明nums数组并未修改 System.out.println(); // 4.修改引用数据类型的数组元素的值 for (String string : strs) { if (string.equals("acd")) { string = "hello world"; System.out.println("已修改"); } } for (String string : strs) { System.out.print(string + "\t"); } // 输出:acd qwe oiu // 说明str数组并未修改 System.out.println(); for (Person person : persons) { if (person.name.equals("张三")) { person.age = 100; System.out.println("已修改"); } } for (Person person : persons) { System.out.print(person + "\t"); } // 输出:Person [name=张三,age=100] Person [name=李四,age=33] Person [name=王五,age=90] // 说明persons数组有修改 System.out.println(); System.out.println("-----------------------------------------------------------"); // int数组相当于: for (int j = 0; j < nums.length; j++) { int i = nums[j]; if (i == 4) { i = 233; } // 所以说修改对于原数组根本没有任何影响 } for (int i : nums) { System.out.print(i + "\t"); } System.out.println(); // String类相当于 for (int j = 0; j < strs.length; j++) { String i = strs[j]; if (i.equals("acd")) { i = "hello world"; } } for (String string : strs) { System.out.print(string + "\t"); } System.out.println(); // Person类相当于: persons = { new Person("张三", 12), new Person("李四", 33), new Person("王五", 90) }; for (int j = 0; j < persons.length; j++) { Person i = persons[j]; if (i.name.equals("张三")) { i.age = 100; // 这里改变的是persons[j].age,而不是persons[j]本身,所以能成功改变 } if (i.name.equals("李四")) { i = new Person("A", 80); // i指向一个新对象,输出结果也毫无变化,不会输出(A,80) } } for (Person person : persons) { System.out.print(person + "\t"); } } } class Person { String name; int age; public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = 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; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
到此这篇关于关于Java的增强for循环修改数组元素的问题的文章就介绍到这了,更多相关Java增强for循环内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!