您的位置:首页 > 编程语言 > Java开发

【java】foreach是如何实现的?

2016-04-06 22:53 519 查看

1.正文

因为想要了解编译器是如何实现foreach功能的,就先写一个foreach循环,看看字节码长啥样。

public class ForEach {

List<String> list;

public void display1(){
for(String s : list){
System.out.println(s);
}
}

}


字节码就长下面这个样子:
// Method descriptor #10 ()V		/*V代表返回值是void*/
// Stack: 2, Locals: 3				/*操作数栈需要2个slot,局部变量表需要3个slot*/
public void display1();
0  aload_0 [this]				/*将this指针推至栈顶*/
1  getfield ambigous.ForEach.list : java.util.List [19]	/*获得域List对象,压入栈顶*/
4  invokeinterface java.util.List.iterator() : java.util.Iterator [21] [nargs: 1]	/*调用interface的iterator方法获得iterator对象*/
9  astore_2						/*将其存到局部变量表的第三个slot中(此时第一个是this,第二个空)*/
10  goto 30						/*跳转*/
13  aload_2						/*将iterator对象推到栈顶*/
14  invokeinterface java.util.Iterator.next() : java.lang.Object [27] [nargs: 1]	/*调用iterator的next方法*/
19  checkcast java.lang.String [33]/*checkcast类型安全检查*/
22  astore_1 [s]					/*将s存到第二块slot*/
23  getstatic java.lang.System.out : java.io.PrintStream [35]	/*获取静态System.out对象*/
26  aload_1 [s]					/*将s推到栈顶*/
27  invokevirtual java.io.PrintStream.println(java.lang.String) : void [41]	/*调用out.println方法*/
30  aload_2						/*将iterator对象推到栈顶*/
31  invokeinterface java.util.Iterator.hasNext() : boolean [47] [nargs: 1]	/*调用iterator.hasNext方法*/
36  ifne 13						/*如果结果非0,即true,跳转*/
39  return						/*返回*/


可以看出对于foreach的执行最终转换成了对iterator的调用。那么我们再对比下显示使用iterator代码的字节码:

public class ForEach {

List<String> list;

public void display1(){
for(String s : list){
System.out.println(s);
}
}

public void display2(){
Iterator<String> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
字节码:

// Method descriptor #10 ()V
// Stack: 2, Locals: 2
public void display2();
0  aload_0 [this]
1  getfield ambigous.ForEach.list : java.util.List [19]
4  invokeinterface java.util.List.iterator() : java.util.Iterator [21] [nargs: 1]
9  astore_1 [it]
10  goto 28
13  getstatic java.lang.System.out : java.io.PrintStream [35]
16  aload_1 [it]
17  invokeinterface java.util.Iterator.next() : java.lang.Object [27] [nargs: 1]
22  checkcast java.lang.String [33]
25  invokevirtual java.io.PrintStream.println(java.lang.String) : void [41]
28  aload_1 [it]
29  invokeinterface java.util.Iterator.hasNext() : boolean [47] [nargs: 1]
34  ifne 13
37  return


看~是不是惊人的相似!其实并不惊人,一切都在预料之中。哈哈。

那么为什么此时局部变量表只需要2个slot就够了呢?

因为第一段代码中slot先后存了this指针、list中的元素即局部变量s、iterator对象;而第二段代码中没有String的临时变量,只有this指针和iterator对象it。

那么两段代码栈为什么都用了两个slot呢?

因为其实第一段代码在23-26的时候栈才存满,栈底是out,栈顶是s。其他时候栈都未满。第二段在13-16的时候栈满,栈底依旧out,栈顶是iterator对象it。



2.References

java forEach实现原理
http://blog.csdn.net/a596620989/article/details/6930479
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: