先来看一段代码
import java.util.List;import java.util.Arrays;public class ForDemo { public static void main(String[] args) { List<String> sources = Arrays.asList("first", "second", "third"); for(String str : sources){ System.out.println(str); } }}
这里的 for循环写法是1.5之后引入的新 feature,允许开发者用简明的方式遍历一个数组中的元素。
这种写法很符合人类思考的方式,如果用 kotlin来写的话从语法上更贴合自然语言的思维,
for(str in sources) { ....}
翻译成自然语言的话,就是"遍历 sources 中的 str 元素"。
不过关于这种简化写法和我们从接触 java第一天开始就学习的传统 for写法有什么区别呢,不知道有深入去看过没有。
深入分析
可能很多人已经知道简化写法其实也是通过 Iterator来遍历元素的,原理很简单,不过我想用最傻的方式来分析这里面的源码实现,掌握这种方式以后可以推此至彼,遇到任何问题都能理出一个思路来。
首先我们看一下ForDemo.java编译后的源码是怎样的,
javap -c ForDemo.class
public class ForDemo { public ForDemo(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: iconst_3 1: anewarray #2 // class java/lang/String 4: dup 5: iconst_0 6: ldc #3 // String first 8: aastore 9: dup 10: iconst_1 11: ldc #4 // String second 13: aastore 14: dup 15: iconst_2 16: ldc #5 // String third 18: aastore 19: invokestatic #6 // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List; 22: astore_1 23: aload_1 24: invokeinterface #7, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 29: astore_2 30: aload_2 31: invokeinterface #8, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 36: ifeq 59 39: aload_2 40: invokeinterface #9, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 45: checkcast #2 // class java/lang/String 48: astore_3 49: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream; 52: aload_3 53: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 56: goto 30 59: return}
重点在 #24 行开始,可以看到这里有 Iterator的方法调用。
关于 Iterator,我们知道任何继承了 Collection的类都需要默认实现一下 Iterator的接口,比如 hasNext(), next(),
从源码上来看的话,可以确定的是 for循环也是通过迭代器来实现遍历的,并且调用了 hasNext和 next方法,
确定了这一点之后就可以猜到,在源码级别的for循环会被编译器优化成下面这样
for(Iterator itr = source.iterator() ; itr.hasNext()) { String str = itr.next(); ....}
举一反三,对于任何的Java代码都可以用 javap 的方式来看编译后的机器码,如果对于某个代码或则语法糖有疑问的话,javap是最简单直接的理解方式。