語法糖是編譯器提供的便利寫法,編譯期轉換為特定位元碼。Java 提供泛型、自動裝箱/拆箱、foreach、可變參數、內部類、枚舉、斷言等語法糖。本文深入剖析 foreach。
範例:List<String> list = new ArrayList<>(); ... for(String s : list) { ... }
用 javap -verbose 反編譯,關鍵發現:編譯器將 foreach 轉換為 Iterator 迭代。實際產生代碼等同於:
for (java.util.Iterator i$ = list.iterator(); i$.hasNext(); ) {
String s = (String) i$.next();
System.out.println(s);
}
註:自定義類若想支援 foreach,必須實作 Iterable 介面。
陣列未實作 Iterable,反編譯發現轉換為傳統索引迴圈:
String[] arr = {"s1","s2"};
String[] arr$ = arr;
for (int len$ = arr$.length, i$ = 0; i$ < len$; i$++) {
String s = arr$[i$];
System.out.println(s);
}
實作 RandomAccess 的集合 (如 ArrayList) 應使用普通 for 迴圈而非 foreach。JDK 文檔明確建議:
經驗法則:若典型實例執行
for (int i=0, n=list.size(); i比 for (Iterator i=list.iterator(); i.hasNext(); ) i.next();更快,則應實作 RandomAccess。
ArrayList 底層為陣列,用 Iterator 會建立額外指標 (next(), hasNext()),增加記憶體開銷與執行效率損耗。建議判斷:
if (list instanceof RandomAccess) {
for (int i=0; i
-c:輸出方法未解析代碼 (位元碼指令)-verbose:輸出堆疊大小、locals/args 數、編譯版本-l:行號與區域變數表-s:內部類型簽名-classpath:指定類搜尋路徑