вторник, 24 ноября 2009 г.

Старое заблуждение о выносе локальной переменной за пределы цикла

Очень старое заблуждение, которое активно пропагандируется некоторыми некомпетентными преподавателями вузов. Заблуждение иллюстрируется следующим кодом:
    public void test1()
    {
        for (int i = 0; i < 20; i++)
        {
            int j = i;
            j++;
        }
    }

    public void test2()
    {
        int j;
        for (int i = 0; i < 20; i++)
        {
            j = i;
            j++;
        }
    }
Считается, что нужно самому выносить локальную переменную из цикла, иначе память под неё будет выделяться на каждой итерации. На самом деле это совсем не так. Компилятор без труда оптимизирует данный кусочек кода. Память будет выделена всего лишь один раз. Причем, это касается не только Java, но и других языков, таких как C, C++ и т.д. Это типичная оптимизация.
Для сомневающихся привожу байт-код обоих методов:
 // Stack: 2, Locals: 3
  public void test1();
     0  iconst_0
     1  istore_1 [i]
     2  goto 13
     5  iload_1 [i]
     6  istore_2 [j]
     7  iinc 2 1 [j]
    10  iinc 1 1 [i]
    13  iload_1 [i]
    14  bipush 20
    16  if_icmplt 5
    19  return
      Line numbers:
        [pc: 0, line: 14]
        [pc: 5, line: 16]
        [pc: 7, line: 17]
        [pc: 10, line: 14]
        [pc: 19, line: 19]
      Local variable table:
        [pc: 0, pc: 20] local: this index: 0 type: my.test.ByteCodeTest
        [pc: 2, pc: 19] local: i index: 1 type: int
        [pc: 7, pc: 10] local: j index: 2 type: int
      Stack map table: number of frames 2
        [pc: 5, append: {int}]
        [pc: 13, same]
  
  // Method descriptor #6 ()V
  // Stack: 2, Locals: 3
  public void test2();
     0  iconst_0
     1  istore_2 [i]
     2  goto 13
     5  iload_2 [i]
     6  istore_1 [j]
     7  iinc 1 1 [j]
    10  iinc 2 1 [i]
    13  iload_2 [i]
    14  bipush 20
    16  if_icmplt 5
    19  return
      Line numbers:
        [pc: 0, line: 24]
        [pc: 5, line: 26]
        [pc: 7, line: 27]
        [pc: 10, line: 24]
        [pc: 19, line: 29]
      Local variable table:
        [pc: 0, pc: 20] local: this index: 0 type: my.test.ByteCodeTest
        [pc: 7, pc: 13] local: j index: 1 type: int
        [pc: 2, pc: 19] local: i index: 2 type: int
      Stack map table: number of frames 2
        [pc: 5, full, stack: {}, locals: {my.test.ByteCodeTest, _, int}]
        [pc: 13, same]
Как мы видим, память выделяется под 2 переменные.

Комментариев нет:

Отправить комментарий