[转载] Java-forEach增强for循环是值传递规则详解
參考鏈接: Java中的for-each循環(huán)
1. 引入?
?正如Java語法意義,變量的傳遞只有值傳遞,雖然變量分為引用變量和基本類型變量,前者更像C中的地址概念。 在學(xué)習(xí)Lambda表達(dá)式的時(shí)候,遇到了試圖在增強(qiáng)for循環(huán)中對原鏈表元素重新賦值失敗的問題,網(wǎng)絡(luò)上也沒有針對此的其他博文,故開此文。?
2. 數(shù)組的增強(qiáng)for循環(huán)?
public class Test1{
?
? ? public static void main(String[] args) {
? ??
? ? ? ? int[] arr = new int[10];
?
? ? ? ? for (int temp :arr){
? ? ? ? ? ? temp++;
? ? ? ? }
?
? ? ? ? for (int temp :arr){
? ? ? ? ? ? System.out.println(temp);
? ? ? ? }
?
?
? ? }
}
?
?控制臺(tái)會(huì)打出10個(gè)0,而不是1,這表明在forEach語句中temp++操作對arr數(shù)組本身沒有任何影響,所以間接證明了,增強(qiáng)for循環(huán)中只是值傳遞。這也可以從原理層面解釋:增強(qiáng)for循環(huán)作為一個(gè)語法糖,其執(zhí)行順序是:對數(shù)組第一個(gè)元素復(fù)制給臨時(shí)變量temp,然后讓temp執(zhí)行循環(huán)中的語句;接著對數(shù)組第二個(gè)元素再次賦值給臨時(shí)變量temp,再次讓其執(zhí)行for循環(huán)中的語句…就這般執(zhí)行至數(shù)組最后一個(gè)元素。所以說,temp接受了數(shù)組元素的值,在++,這對于數(shù)組中的數(shù)字沒有任何影響。所以說如果要進(jìn)行原數(shù)組的更改,更好的方式是使用普通的for循環(huán)。?
3. ArrayList的增強(qiáng)for循環(huán)?
?代碼需求是將其list中的String類型對象從小寫轉(zhuǎn)換為大寫;?
public class LowercaseToUppercase{
?
? ? public static void main(String[] args) {
?
? ? ? ? List<String> list = Arrays.asList("hello", "world", "hello world");
?
? ? ? ? list.forEach(i -> {
? ? ? ? ? ? i = i.toUpperCase();
? ? ? ? });
?
? ? ? ? list.forEach(System.out::println);
? ? }
}
?
?
?控制還是輸出小寫的String類型對象,“hello”, “world”, “hello world”,倘若你查看forEach方法,你可以發(fā)現(xiàn)此原理和第一個(gè)例子的數(shù)組遍歷實(shí)現(xiàn)原理是一樣的,i作為一個(gè)中間變量,是臨時(shí)存放了String類型的引用變量,但是對原list沒有任何影響,如下面被調(diào)用的forEach方法的默認(rèn)實(shí)現(xiàn)代碼(其中t就是被定義為泛型類型T的臨時(shí)變量)。 ?一個(gè)易錯(cuò)點(diǎn):很多人認(rèn)為:因?yàn)镾tring內(nèi)部是final修飾的數(shù)組,不能被重新賦值,臨時(shí)變量i只能指向新的引用對象,所以上述代碼功能才不能被實(shí)現(xiàn),這是不對的,其真正的原因是對臨時(shí)變量賦值是無法達(dá)到預(yù)期效果。正確的理解是:對臨時(shí)變量進(jìn)行賦值,只能使臨時(shí)變量指向新的對象,而對原String對象沒有任何作用。即使將上述代碼中ArrayList的對象類型由String換成StringBuilder類,在這樣的情況下,雖然同一個(gè)```StringBuilder``對象的值是可以被修改的,但是使用對臨時(shí)變量賦值的操作還是不能對原數(shù)據(jù)結(jié)構(gòu)元素值造成影響。?
?如果要實(shí)現(xiàn),需要調(diào)用StringBuilder類對象的方法,一般是返回this對象,代碼如下所示:?
public class LowercaseToUppercase {
?
? ? public static void main(String[] args) {
? ?
? ? ? ? List<StringBuilder> list3= Arrays.asList(new StringBuilder("hello"),
? ? ? ? new StringBuilder("world"),new StringBuilder("hello world"));
?
? ? ? ? list3.forEach(i->
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? String str= i.toString().toUpperCase();
? ? ? ? ? ? ? ? ? ? i.replace(0,str.length(),str);
? ? ? ? ? ? ? ? }
?
? ? ? ? );
? ? ? ? list3.forEach(System.out::println);
?
? ? }
}
?
?
?控制臺(tái)輸出了大寫的字符串,說明我們成功將StringBuilder類型由小寫轉(zhuǎn)化為大寫,不過遍歷中的臨時(shí)變量i的賦值語句并不存在,而是調(diào)用其方法,返回this對象,才實(shí)現(xiàn)了轉(zhuǎn)換。?
?下面這個(gè)代碼塊是Java集合的forEach方法默認(rèn)實(shí)現(xiàn),一定要讀懂它:?
? ?default void forEach(Consumer<? super T> action) {
? ? ? ? Objects.requireNonNull(action);
? ? ? ? for (T t : this) {
? ? ? ? ? ? action.accept(t);
? ? ? ? }
? ? }
?
?可見Java在foreach語言的執(zhí)行上保證了原數(shù)據(jù)結(jié)構(gòu)的安全性,如果確定要更改原數(shù)據(jù)結(jié)構(gòu),請使用傳統(tǒng)的for循環(huán)。并且我們在foreach語句中可以采用復(fù)制給新數(shù)據(jù)結(jié)構(gòu)的方法實(shí)現(xiàn)類似的作用:?
? ? ? ? List<String> list2 = new ArrayList<>();
?
? ? ? ? list.forEach(item->list2.add(item.toUpperCase()));
?
? ? ? ? list2.forEach(System.out::println);
?
?倘若返回list2,那么和傳統(tǒng)的for語句也是類似的效果。
總結(jié)
以上是生活随笔為你收集整理的[转载] Java-forEach增强for循环是值传递规则详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用idea建立jsp项目_用idea创建
- 下一篇: [转载] 详解Java中的泛型