zoukankan      html  css  js  c++  java
  • Java JDK1.5的新特性之for-each循环的底层原理

    今天给大家分享一下for-each 循环的底层原理,故事还得从字节码反汇编和反编译说起...

    首先看一下Java JDK1.5 的新特性

    • 泛型: ...
    • for-each. ...
    • 自动拆箱和装箱功能 ...
    • 枚举: ...
    • 可变参数 ...
    • 静态导入 ...
    • 线程并发库

    对于字节码反汇编,可以使用 JDK 自带的工具 javap
    首先看一下 javap 有哪些指令以及用法

    $ javap
    用法: javap <options> <classes>
    其中, 可能的选项包括:
      -help  --help  -?        输出此用法消息
      -version                 版本信息
      -v  -verbose             输出附加信息
      -l                       输出行号和本地变量表
      -public                  仅显示公共类和成员
      -protected               显示受保护的/公共类和成员
      -package                 显示程序包/受保护的/公共类
                               和成员 (默认)
      -p  -private             显示所有类和成员
      -c                       对代码进行反汇编
      -s                       输出内部类型签名
      -sysinfo                 显示正在处理的类的
                               系统信息 (路径, 大小, 日期, MD5 散列)
      -constants               显示最终常量
      -classpath <path>        指定查找用户类文件的位置
      -cp <path>               指定查找用户类文件的位置
      -bootclasspath <path>    覆盖引导类文件的位置
    

      

    由此可见,在我们拿到字节码文件之后,使用javap -c 字节码文件位置,即可进行反汇编

    其实 for-eachjdk 1.5 的语法糖,它可以迭代集合和数组

    1.for-each 迭代集合
    首先来看 for-each 迭代集合

    public static void main(String[] args) {
    	List<String> a = new ArrayList<>();
    	a.add("1");
    	a.add("2");
    	a.add("3");
    
    	for (String temp : a) {
    		System.out.print(temp);
    	}
    }
    

      

    javap 反汇编这段代码

    $ javap -c ForeachTest.class
    Compiled from "ForeachTest.java"
    public class cn.ixan.design.ForeachTest {
      public cn.ixan.design.ForeachTest();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]);
        Code:
           0: new           #2                  // class java/util/ArrayList
           3: dup
           4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
           7: astore_1
           8: aload_1
           9: ldc           #4                  // String 1
          11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
          16: pop
          17: aload_1
          18: ldc           #6                  // String 2
          20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
          25: pop
          26: aload_1
          27: ldc           #7                  // String 3
          29: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
          34: pop
          35: aload_1
          36: invokeinterface #8,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
          41: astore_2
          42: aload_2
          43: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
          48: ifeq          71
          51: aload_2
          52: invokeinterface #10,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
          57: checkcast     #11                 // class java/lang/String
          60: astore_3
          61: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
          64: aload_3
          65: invokevirtual #13                 // Method java/io/PrintStream.print:(Ljava/lang/String;)V
          68: goto          42
          71: return
    }
    

      

    由第 36 行,第 43 行,第 52 行可知,迭代集合使用到了 Iterator

    然后使用 idea 查看字节码文件,发现 foreach 遍历集合运用迭代器

    public static void main(String[] args) {
    	List<String> a = new ArrayList();
    	a.add("1");
    	a.add("2");
    	a.add("3");
    	Iterator var2 = a.iterator();
    
    	while(var2.hasNext()) {
    		String temp = (String)var2.next();
    		System.out.print(temp);
    	}
    
    }
    

      

    2.for-each 迭代数组
    我们知道集合继承 Iterable 接口,使用使用 iterator 迭代集合,
    那么数组没有继承 Iterable 接口,for-each 是如何迭代它呢?

    首先来看 for-each 迭代数组

    public static void main(String[] args) {
    	String[] arr = {"1","2"};
    	for(String e : arr){
    		System.out.println(e);
    	}
    }
    

      

    javap 反汇编这段代码

    $ javap -c ForeachTest.class
    Compiled from "ForeachTest.java"
    public class cn.ixan.design.ForeachTest {
      public cn.ixan.design.ForeachTest();
        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_2
           1: anewarray     #2                  // class java/lang/String
           4: dup
           5: iconst_0
           6: ldc           #3                  // String 1
           8: aastore
           9: dup
          10: iconst_1
          11: ldc           #4                  // String 2
          13: aastore
          14: astore_1
          15: aload_1
          16: astore_2
          17: aload_2
          18: arraylength
          19: istore_3
          20: iconst_0
          21: istore        4
          23: iload         4
          25: iload_3
          26: if_icmpge     49
          29: aload_2
          30: iload         4
          32: aaload
          33: astore        5
          35: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
          38: aload         5
          40: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          43: iinc          4, 1
          46: goto          23
          49: return
    }
    

      

    和迭代集合不同,没有出现 Iterator,说明没有使用迭代器
    第 18 行 arraylength,可能使用到了数组的 length 属性

    使用 idea 反编译查看,发现 for-each 遍历数组是经典 for 循环

    public static void main(String[] args) {
    	String[] arr = new String[]{"1", "2"};
    	String[] var2 = arr;
    	int var3 = arr.length;
    
    	for(int var4 = 0; var4 < var3; ++var4) {
    		String e = var2[var4];
    		System.out.println(e);
    	}
    
    }
    

      

    总结:  1.for-each 迭代集合时,使用的是迭代器迭代集合。
         2.for-each 迭代数组时,使用的是经典for循环。

     

  • 相关阅读:
    Android开发 使用 adb logcat 显示 Android 日志
    【嵌入式开发】向开发板中烧写Linux系统-型号S3C6410
    C语言 结构体相关 函数 指针 数组
    C语言 命令行参数 函数指针 gdb调试
    C语言 指针数组 多维数组
    Ubuntu 基础操作 基础命令 热键 man手册使用 关机 重启等命令使用
    C语言 内存分配 地址 指针 数组 参数 实例解析
    CRT 环境变量注意事项
    hadoop 输出文件 key val 分隔符
    com.mysql.jdbc.exceptions.MySQLNonTransientConnectionException: Too many connections
  • 原文地址:https://www.cnblogs.com/ixan/p/12290358.html
Copyright © 2011-2022 走看看