本篇是我對於foreach語句(增強for)的總結:
我的總結流程如下:
1.先整體說明增強for遍歷集合與數組之間的區別。
2.通過一維數組來說明(給出反編譯的源碼,形成對照)。
3.通過二維數組來說明(給出反編譯的源碼,形成對照)。
4.通過三維數組來說明(給出反編譯的源碼,形成對照)。
5.通過集合來說明(給出反編譯的源碼,形成對照)。
6.反編譯的介紹以及網站分享。
7.結束。
一.增強for遍歷集合與數組之間的區別
其實之前在我還沒有學習到迭代器之前我已經總結過這個知識點了,但是在我了解過迭代器之后,我決定將之刪掉重寫.問過很多人,都說foreach語句無非就是一直在使用迭代器,可是在我真正測試了之后,才發現,並不像大多數人想的那樣。
因為我了解到了迭代器的使用只能是在集合中(下面是API文檔中的一些解釋):
並且對之有所了解的都應該知道,迭代器只是一個接口,他的使用是要通過其實現類來完成的,而只有Collection集合或者其子類才能通過調用iterator方法返回一個實現類對象。
所以說,只有集合是通過迭代器來遍歷的,但是數組就不是了,因為數組與集合並不是同一個概念。
再來說說數組與集合的不同之處吧:
1.集合的長度可變,而數組的長度是不可變的。
2.集合可以存儲對象與基本類型數據,但是數組只能存儲基本類型數據。
二.通過一維數組來說明
普通代碼:
public class Demo9 { public static void main(String[] args) { int[] a= {1,2,3,4,4,5}; for(int i:a) { System.out.println(i); } } }
反編譯后的代碼:
public class Demo10 { public static void main(String[] args) { int[] a = new int[]{1, 2, 3, 4, 4, 5}; //按照計算機的創建數組的標准格式創建一個數組 int[] var5 = a; //相當於復制a數組 int var4 = a.length; //記錄a數組的長度 for(int var3 = 0; var3 < var4; ++var3) { int i = var5[var3]; //將a數組元素逐個賦值給i System.out.println(i); } } }
通過反編譯代碼,很明顯可以看到,對於數組使用增強for與迭代器是沒有任何關系的(這篇就翻過啦,哈哈),我把解釋全部寫在反編譯的代碼中了。
三.通過二維數組來說明(這將是我說明的重點)
普通代碼:
public class Demo6 { public static void main(String[] args) { int[][] a= {{1,2,3},{2,5,3}}; for(int i[]:a) { //此處用了兩次foreach語句,具體原因我們通過反編譯代碼說明 for(int e:i) { System.out.println(e); } } System.out.println(a.length); } }
反編譯代碼:
public class Demo5 { public static void main(String[] args) { int[][] a = new int[][]{{1, 2, 3}, {2, 5, 3}}; //這里仍是一個標准的二維數組創建格式 int[][] var5 = a; //又復制了一遍數組 int var4 = a.length; //把a的長度2給了var4 for(int var3 = 0; var3 < var4; ++var3) { //這個循環進行兩次 int[] i =var5[var3]; //此處是我理解的一個困難之處,但是我已克服,會在下面說出我的見解
int[] var9 = i; //又復制了一次數組 int var8 = i.length; //給長度 for(int var7 = 0; var7 < var8; ++var7) { int e = var9[var7]; //這里就和一維數組完全一樣了 System.out.println(e); } } } }
我會通過語言描述,將我所理解到的,二維數組的foreach遍歷中的我之前不理解但現在已解決的地方說出來:
int[] i =var5[var3]; int[] var9 = i;
i.length=3;
i數組輸出出來是二維數組中的一維數組(就是每一個大括號中的內容)
此處最初令我十分不解。因為我大一上學期是學c語言的,在我的腦海中數組這些知識都應該是通用的,但是我卻沒見過這種方式,在我最初的理解中,我之所以遇到困難,是因為我一直糾結於將一個地址直接給一個數組是不合適的,但是我后來又試了一下,發現如果我們將代碼寫成這樣就很好理解了。
int[] i =new int[5]; i=var5[var3];
因為我想通過這樣的方式來幫助我理解的話,我事先必須先定義一個數組,出於嘗試的態度,我將它的初始長度設為5,但上文代碼中,我們知道最后i的長度是3,最先我以為這里的i是被覆蓋了,后來才發現並不是這樣,因為var5[var3]是二位數組的行的首地址,所以只是改變了i的指向,他所指向的變成了a數組的每一行的行首,所以他就相當於,通過遍歷,不斷地復制二維數組每一行的元素。
當然有人會問了,你怎么去確定,他的長度為啥就一定是與二維數組第一行長度一樣?
其實,我們會發現在二維數組中,每一行的首地址都是不一樣的,我所謂的不一樣是沒有規律的,就是他們並不是整個二維數組連在一起的,而是以行為單位的連在一起的。
四.通過三維數組說明問題
普通代碼:
public class Demo10 { public static void main(String[] args) { int[][][] a= {{{1,2,3},{2,3}},{{2,3},{2,6}},{{3,4},{5,6}}}; for(int[][] b:a) { for(int[] c:b) { for(int d:c) { System.out.println(d); } } } } }
此處我決定只是通過普通代碼的方式來說明問題,因為計算機總是會自己創造出一些變量,對於三維數組來說,這些變量就更多了(看看二維數組,唉。。),這樣只會是我們的理解更加的不具體,不直觀。
其實我們不難發現,無論多高維度的數組,將其輸出的格式都是一樣的,最終的輸出語句一定是在一維數組中的。
五.通過集合說明
普通代碼:
import java.util.ArrayList; import java.util.Collection; public class Demo8 { public static void main(String[] args) { Collection cc=new ArrayList(); cc.add("哈哈"); cc.add("嘻嘻"); cc.add("哼哼"); cc.add(1); for(Object s:cc) { System.out.println(s); } } }
反編譯代碼:
import java.util.ArrayList; import java.util.Iterator; public class Demo8 { public static void main(String[] args) { ArrayList cc = new ArrayList(); cc.add("鍝堝搱"); //這里的字符串應該只是機器碼的緣故,我並沒有深究 cc.add("鍢誨樆"); cc.add("鍝煎摷"); cc.add(Integer.valueOf(1)); Iterator var3 = cc.iterator(); while(var3.hasNext()) { Object s = var3.next(); System.out.println(s); } } }
很明顯這次我們發現,用增強for遍歷集合反編譯的格式完全不一樣了,並且還用到了迭代器,並且我並沒有使用泛型,即沒有給出數據類型,這樣也更好理解一些。
對於其中的一些關於集合的知識,比如說迭代器的相關方法呀,之類的我就不在本篇說啦,對於集合我還是會總結的。
六.反編譯的使用
何為反編譯,我的理解就是將那些隱藏句式的全部代碼顯現出來,對於foreach語句的理解若是沒有反編譯我是絕對不可能做出來的,最初的時候,我試着用javap進行反匯編但是我發現里面的東西並不是我想看到的,所以我花了一個小時,去找那種我想要的反編譯軟件,最后發現不是安裝太麻煩,就是不適合我。。。。。。。。。
好在偶然發現了一個網站,很好使,完全就是用來進行我所需要的那種反編譯的,所以如果看我的文章還是不太理解的話,可以在評論區與我進行討論,或者通過這個網站形成你自己的理解,網址在這了(http://javare.cn/)。
七.結束
其實之前,我已經總結過該知識點了,並且看的人還挺多的,那時我也是初學,沒有思考的太過深入,所以就按照自己所想總結了一下,但是昨天翻看的時候發現總結的那叫一個慘不忍睹,一點邏輯性都沒有,這樣其實對於那些耐着性子,看我這個菜鳥的博客的人挺不好的,所以我就刪掉決定重寫,我並不能保證該篇中就沒有一點問題,但是這絕對是我深思熟慮的結果。還是老樣子,加油,慢慢變強吧。