Java如何知道如何迭代数组

Sap*_*Sun 7 java arrays foreach

String[] strs = new String[] { "1", "2", ... , "6" };

for (String s : strs) {
    System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)

这是关于java internals的问题.

在上面的代码示例中,foreach循环如何计算出数组的长度?数组实际上是内部对象还是使用sizeof前端程序员无法访问的东西?

我有一种感觉,我只是错过了一些愚蠢的东西,但我觉得它也很酷.:-)

Ree*_*ore 11

我编译了以下代码:

public class ArrayIterator
{
    public static void main(String[] argv)
    {
        String[] strs = new String[] { "1", "2", "3", "4", "5" };
        enhancedPrint(strs);
        normalPrint(strs);
    }

    public static void enhancedPrint( String[] strs )
    {
        for (String s : strs)
        {
            System.out.println(s);
        }
    }

    public static void normalPrint( String[] strs )
    {
        String[] localArray = strs;
        int len = localArray.length;
        for (int i = 0; i < len; i++)
        {
            String s = localArray[i];
            System.out.println(s);
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

这是javap -c ArrayIterator迭代函数的反汇编()字节码:

增强的印刷品:

public static void enhancedPrint(java.lang.String[]);
  Code:
   0:   aload_0
   1:   astore_1
   2:   aload_1
   3:   arraylength
   4:   istore_2
   5:   iconst_0
   6:   istore_3
   7:   iload_3
   8:   iload_2
   9:   if_icmpge   31
   12:  aload_1
   13:  iload_3
   14:  aaload
   15:  astore  4
   17:  getstatic   #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload   4
   22:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  iinc    3, 1
   28:  goto    7
   31:  return
Run Code Online (Sandbox Code Playgroud)

循环的正常:

 public static void normalPrint(java.lang.String[]);
  Code:
   0:   aload_0
   1:   astore_1
   2:   aload_1
   3:   arraylength
   4:   istore_2
   5:   iconst_0
   6:   istore_3
   7:   iload_3
   8:   iload_2
   9:   if_icmpge   31
   12:  aload_1
   13:  iload_3
   14:  aaload
   15:  astore  4
   17:  getstatic   #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload   4
   22:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  iinc    3, 1
   28:  goto    7
   31:  return
Run Code Online (Sandbox Code Playgroud)

如您所见,在这两种情况下,编译器都会加载数组length(strs.length)并对其进行循环.我们看到增强的for-each循环,在Array的情况下是用于循环数组长度的语法糖(而不是在Object使用Iterator的情况下).


我已经编辑了'normal'for循环,因此它不那么惯用,但是它与增强的for循环具有相同的字节码.对于所有意图和目的,循环版本的常规是编译器在为每个循环编译增强时生成的.