【问题标题】:How Does Java Know How to Iterate an ArrayJava如何知道如何迭代数组
【发布时间】:2011-06-01 09:42:06
【问题描述】:
String[] strs = new String[] { "1", "2", ... , "6" };

for (String s : strs) {
    System.out.println(s);
}

这是一个关于java内部的问题。

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

我有一种感觉,我只是错过了一些愚蠢的东西,但我认为它也可能很酷。 :-)

【问题讨论】:

  • +1 个有趣的问题,完全没有重复。
  • 不完全。我已经知道它是可迭代的,但是迭代器怎么知道什么时候停止迭代呢?

标签: java arrays foreach


【解决方案1】:

我编译了以下代码:

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);
        }
    }
} 

这是迭代函数的反汇编 (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

一个普通的for循环:

 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

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


我已经编辑了“普通”for 循环,使其不那么惯用,但它具有与增强的 for 循环相同的字节码。出于所有意图和目的,正常的 for 循环版本是编译器在为每个循环编译增强型时生成的。

【讨论】:

    【解决方案2】:

    是的,有一些类似于 C++ 的sizeof 运算符——它是length 实例变量(它给出了数组中的元素数量,而不是字节大小。) length 字段始终是数组的公共成员,因此 Java 程序员可以访问它。

    是的,数组是objects,而不仅仅是内部。

    (更广泛地说,for 循环语法按照 org.life.java 链接到的question 中的描述工作;但这并不是您要问的。)

    【讨论】:

      【解决方案3】:

      是的,数组是具有“长度”字段的对象。 Java 语言规范:http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#64347

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-21
        • 2018-02-26
        • 2016-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多