先来看一段代码
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是最简单直接的理解方式。