Java的增強(qiáng)for循環(huán)修改數(shù)組元素的問題小結(jié)
曾經(jīng)沒怎么多想過for each有什么特殊的地方,以為就是for循環(huán)的簡便寫法,直到今天寫力扣發(fā)現(xiàn)了不對勁,使用for each就是過不了,而用正規(guī)for循環(huán)就過了,決定來好好了解一下for each。
而有時(shí)候?qū)懺鰪?qiáng)for循環(huán)又可以修改屬性
最后發(fā)現(xiàn),是否能理解for each的修改與是否理解Java是值傳遞有很大的關(guān)系。
(完整代碼放在最后)
決定從基本數(shù)據(jù)類型和引用數(shù)據(jù)類型兩種類型來看。
首先簡單看一下for each的遍歷:
自定義了一個(gè)Person類,有name(String)和age(int)兩個(gè)屬性。
用int數(shù)組代表基本數(shù)據(jù)類型的數(shù)組,用String類和Person類代表引用數(shù)據(jù)類型的數(shù)組
輸出結(jié)果都放在了注釋里面:
public class Main { public static void main(String[] args) { // 1.能成功遍歷基本數(shù)據(jù)類型的數(shù)組元素 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.能成功遍歷引用數(shù)據(jù)類型的數(shù)組元素 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來修改數(shù)據(jù):(和上面代碼重復(fù)的內(nèi)容不再寫)
public class Main { public static void main(String[] args) { //這些數(shù)據(jù)沒有變 int[] nums = { 1, 2, 3, 4, 5 }; String[] strs = { "acd", "qwe", "oiu" }; Person[] persons = { new Person("張三", 12), new Person("李四", 33), new Person("王五", 90) }; // 3.修改基本數(shù)據(jù)類型的數(shù)組元素的值 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數(shù)組并未修改 System.out.println(); // 4.修改引用數(shù)據(jù)類型的數(shù)組元素的值 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數(shù)組并未修改 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數(shù)組有修改 System.out.println(); } }
結(jié)果:int數(shù)組和String數(shù)組多沒能成功修改,而只有Person數(shù)組成功修改了
為什么Person數(shù)組能修改成功呢?因?yàn)镴ava是值傳遞。能理解這個(gè)非常重要!
(理解的朋友可以跳過下面這一段)
理解Java是值傳遞:
首先什么是值傳遞,什么是引用傳遞呢?
- 值傳遞是指在調(diào)用函數(shù)時(shí)將實(shí)際參數(shù)復(fù)制一份傳遞到函數(shù)中,這樣在函數(shù)中如果對參數(shù)進(jìn)行修改,將不會影響到實(shí)際參數(shù)。
- 引用傳遞是指在調(diào)用函數(shù)時(shí)將實(shí)際參數(shù)的地址直接傳遞到函數(shù)中,那么在函數(shù)中對參數(shù)所進(jìn)行的修改,將影響到實(shí)際參數(shù)。
主要區(qū)別就在于是否將實(shí)際參數(shù)復(fù)制
那為什么說Java是值傳遞呢?按照這么說,Java其實(shí)是將實(shí)際參數(shù)復(fù)制過傳遞到函數(shù)中的呀!
有人舉例說把int等基本數(shù)據(jù)類型作為參數(shù),并不能修改實(shí)參的值,能說明Java是值傳遞,而傳遞Person這種自定義的類,在函數(shù)中修改屬性之后,在主函數(shù)中調(diào)用卻能成功修改,這并不能說明Java是值傳遞,反而像引用傳遞呀?
曾經(jīng)看到一個(gè)例子:
- 你的朋友借給你一把鑰匙,你朋友就相當(dāng)于主函數(shù),你相當(dāng)于主函數(shù)中調(diào)用的另一個(gè)函數(shù),鑰匙就是實(shí)參,你這個(gè)函數(shù)就相當(dāng)于進(jìn)入朋友家中,干一些事情之后離開。你拿著這把鑰匙,能打開他們家的大門,于是你進(jìn)了他們家,砸壞了他們家的電視機(jī)(相當(dāng)于修改Person類的屬性)。當(dāng)這個(gè)函數(shù)結(jié)束的時(shí)候,就相當(dāng)于你已經(jīng)離開了你朋友的家中。你朋友拿著鑰匙打開了自家的門,發(fā)現(xiàn)電視機(jī)被砸壞了(相當(dāng)于你在輸出端看到在主屬性Print的Person的屬性值被修改了),
于是朋友把你揍了一頓。
所以說在子函數(shù)中修改屬性,這個(gè)屬性并非是傳遞進(jìn)來的參數(shù)。傳遞進(jìn)來的參數(shù)是鑰匙!而不是會被砸的電視機(jī)!
Java是值傳遞可以理解為,你拿著你朋友家的鑰匙又復(fù)刻了一把,所以現(xiàn)在有兩把鑰匙。你和你朋友都能用兩把鑰匙打開朋友家的門!
意思就是有兩個(gè)引用同時(shí)指向了同一個(gè)地址,第二個(gè)復(fù)制的引用正是子函數(shù)中的局部變量。無論是用哪一個(gè)引用對屬性修改,都能直接在內(nèi)存中修改,于是會出現(xiàn)傳遞Person類修改屬性會看到成功修改的結(jié)果。
如何體現(xiàn)值傳遞的特征呢——修改傳遞過來的值,并不會影響原來的對象:
就好比,你在復(fù)刻的鑰匙上寫下自己的名字,你朋友的鑰匙上并不會出現(xiàn)你的名字。
就意味著你用子函數(shù)中的引用去指向一個(gè)新對象,而主函數(shù)中的引用并不會去指向那個(gè)新對象一樣,還是指向原來的對象。
所以說Java是值傳遞,而并發(fā)引用傳遞!
回到增強(qiáng)for循環(huán):
for(元素類型t 元素變量x : 遍歷對象obj){ 引用了x的java語句; }
增強(qiáng)for循環(huán)的元素變量x,就是一個(gè)局部變量,它是引用數(shù)組當(dāng)前元素引用的副本(就相當(dāng)于上文所說的你復(fù)刻朋友的鑰匙),或者是基本數(shù)據(jù)類型的值的副本。
可以這么理解:
int[] nums = { 1, 2, 3, 4, 5 }; for (int i : nums) { if (i == 4) { i = 233; } } //相當(dāng)于: for(int j=0;j<nums.length;j++){ int i=nums[j]; if(i==4){ i=233; } //所以說修改對于原數(shù)組根本沒有任何影響 }
對于String數(shù)組相當(dāng)于:
for (int j = 0; j < strs.length; j++) { String i = strs[j]; if (i.equals("acd")) { i = "hello world"; } } //String類是不可變對象,所以這里也沒有任何影響 //輸出:acd qwe oiu
對于Person類相當(dāng)于:
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指向一個(gè)新對象,輸出結(jié)果也毫無變化,不會輸出(A,80) } }
總而言之:如果想要修改元素就用正規(guī)for循環(huán),不要使用增強(qiáng)for循環(huán)。
所有的代碼:
public class Main { public static void main(String[] args) { // 1.能成功遍歷基本數(shù)據(jù)類型的數(shù)組元素 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.能成功遍歷引用數(shù)據(jù)類型的數(shù)組元素 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.修改基本數(shù)據(jù)類型的數(shù)組元素的值 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數(shù)組并未修改 System.out.println(); // 4.修改引用數(shù)據(jù)類型的數(shù)組元素的值 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數(shù)組并未修改 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數(shù)組有修改 System.out.println(); System.out.println("-----------------------------------------------------------"); // int數(shù)組相當(dāng)于: for (int j = 0; j < nums.length; j++) { int i = nums[j]; if (i == 4) { i = 233; } // 所以說修改對于原數(shù)組根本沒有任何影響 } for (int i : nums) { System.out.print(i + "\t"); } System.out.println(); // String類相當(dāng)于 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類相當(dāng)于: 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指向一個(gè)新對象,輸出結(jié)果也毫無變化,不會輸出(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 + "]"; } }
到此這篇關(guān)于關(guān)于Java的增強(qiáng)for循環(huán)修改數(shù)組元素的問題的文章就介紹到這了,更多相關(guān)Java增強(qiáng)for循環(huán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mac Book中Java環(huán)境變量設(shè)置的方法
本文給大家介紹mac book 中設(shè)置java環(huán)境變量的方法,非常不錯,具有參考借鑒價(jià)值,需要的朋友參考下2017-04-04java判斷今天,昨天,前天,不能用秒間隔的簡單實(shí)例
下面小編就為大家?guī)硪黄猨ava判斷今天,昨天,前天,不能用秒間隔的簡單實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03Java 利用DeferredResult實(shí)現(xiàn)http輪詢實(shí)時(shí)返回?cái)?shù)據(jù)接口
這篇文章主要介紹了Java 利用 DeferredResult 實(shí)現(xiàn) http 輪詢實(shí)時(shí)返回?cái)?shù)據(jù)接口,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-03-03JDBC連接Mysql的5種方式實(shí)例總結(jié)
JDBC是Java DataBase Connectivity技術(shù)的簡稱,是一種可用于執(zhí)行 SQL語句的Java API,下面這篇文章主要給大家介紹了關(guān)于JDBC連接Mysql的5種方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04JDK14新特性之switch表達(dá)式的實(shí)現(xiàn)
這篇文章主要介紹了JDK14新特性之switch表達(dá)式的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Java實(shí)現(xiàn)基于token認(rèn)證的方法示例
這篇文章主要介紹了Java實(shí)現(xiàn)基于token認(rèn)證的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08