Как Java знает, как перебирать массив - PullRequest
7 голосов
/ 30 декабря 2010
String[] strs = new String[] { "1", "2", ... , "6" };

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

Это вопрос о внутренностях Java.

Как в приведенном выше примере кода цикл foreach определяет длину массива? Массивы на самом деле являются объектами внутри или используют такие вещи, как sizeof, которые недоступны для программистов переднего плана?

У меня такое ощущение, что я просто скучаю по чему-то глупому, но я думаю, это тоже может быть круто. : -)

Ответы [ 3 ]

11 голосов
/ 30 декабря 2010

Я скомпилировал следующий код:

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

Нормальное значение для цикла:

 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.Для всех намерений и целей нормальная версия цикла - это то, что генерирует компилятор, когда компилирует расширенный для каждого цикла.

3 голосов
/ 30 декабря 2010

Да, есть что-то похожее на оператор C ++ sizeof - это переменная экземпляра length (которая дает количество элементов в массиве, а не размер в байт.) Поле length всегда является открытым членом массива, поэтому оно доступно для Java-программистов.

И да, массивы - это объекты , а не только внутренние.

(В более широком смысле синтаксис цикла for работает, как описано в вопросе , с которым связан org.life.java; но это не совсем то, о чем вы спрашивали.)

1 голос
/ 30 декабря 2010

Да, массивы - это объекты с полем «длина».Спецификация языка Java: http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#64347

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...