牛骨文教育服务平台(让学习变的简单)
博文笔记

【java】foreach是如何实现的?

创建时间:2016-04-06 投稿人: 浏览次数:4023

因为想要了解编译器是如何实现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。

java forEach实现原理

http://blog.csdn.net/a596620989/article/details/6930479


声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。