создание окончательных переменных внутри цикла - PullRequest
47 голосов
/ 04 марта 2009

это разрешено в Java:

for(int i=0;i<5;i++){
  final int myFinalVariable = i;
}

Ключевое слово моего вопроса: final. Разрешено ли делать окончательную переменную, которая меняется при каждом запуске цикла? Мне было интересно, потому что final говорит, что вы не можете изменить значение переменной (вызывая только myFinalVariable = i), но я переопределяю всю переменную с помощью final int.

Это две совершенно разные переменные, имеющие только одно и то же имя - переменная из предыдущего цикла цикла уже движется по дороге к сборщику мусора?

Ответы [ 5 ]

82 голосов
/ 04 марта 2009

Да, это разрешено. Ключевое слово final означает, что вы не можете изменить значение переменной в ее области действия . В качестве примера цикла вы можете представить, как переменная выходит из области видимости в нижней части цикла, а затем возвращается в область видимости с новым значением в верхней части цикла. Присвоение переменной в цикле не будет работать.

12 голосов
/ 04 марта 2009

Вы правы, для каждой итерации в цикле вы создаете новую переменную. Переменные имеют одинаковое имя, но это нормально, потому что они не находятся в одной области видимости. Следующий пример будет не работать:

final int myFinalVariable = 0;
for(int i=0;i<5;i++){
  myFinalVariable = i;
}
9 голосов
/ 04 марта 2009

Переменная - это просто место в стеке. Старайтесь, чтобы ваши переменные были как можно меньше, и сделайте их окончательными. Однако область видимости и финал - это просто вещи исходного кода ... с точки зрения генерации кода / виртуальной машины они на самом деле не имеют никакого значения.

В вашем конкретном примере с использованием "int" мусор не создается. Однако, если бы это были объекты, создаваемые тогда, то для обоих случаев количество мусора и время, когда мусор будет пригоден для очистки, были бы одинаковыми.

Возьмите следующий код:

public class X
{
    public static void main(final String[] argv)
    {
        foo();
        bar();
    }

    private static void foo()
    {
        for(int i=0;i<5;i++)
        {
            final int myFinalVariable = i;
        }
    }

    private static void bar()
    {
        for(int i=0;i<5;i++)
        {
            int myFinalVariable = i;
        }
    }
}

Компилятор выдает идентичный байт-код для каждого метода:

public class X extends java.lang.Object{
public X();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #2; //Method foo:()V
   3:   invokestatic    #3; //Method bar:()V
   6:   return

private static void foo();
  Code:
   0:   iconst_0
   1:   istore_0
   2:   iload_0
   3:   iconst_5
   4:   if_icmpge       15
   7:   iload_0
   8:   istore_1
   9:   iinc    0, 1
   12:  goto    2
   15:  return

private static void bar();
  Code:
   0:   iconst_0
   1:   istore_0
   2:   iload_0
   3:   iconst_5
   4:   if_icmpge       15
   7:   iload_0
   8:   istore_1
   9:   iinc    0, 1
   12:  goto    2
   15:  return

}

Добавление другого метода, который объявляет переменную вне цикла, дает вам немного другой байт-код из-за порядка объявления переменных). Обратите внимание, что в этой версии переменная не может быть окончательной. Эта последняя версия - не лучший способ (последняя переменная внутри цикла - лучшая, если вы можете это сделать):

private static void car()
{
    int myFinalVariable;

    for(int i=0;i<5;i++)
    {
        myFinalVariable = i;
    }
}

private static void car();
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   iconst_5
   4:   if_icmpge       15
   7:   iload_1
   8:   istore_0
   9:   iinc    1, 1
   12:  goto    2
   15:  return

}
2 голосов
/ 07 июля 2013

Переменные, объявленные внутри цикла, имеют область действия только до однократного выполнения цикла.

Объявление переменной как конечной в цикле не делает разницы для переменной внутри цикла, но если мы объявим переменную вне цикла с модификатором final, то значение, присвоенное типу примитива или объекту, назначенному ссылочной переменной, не может быть изменены.

В приведенном ниже примере нет проблем с первыми двумя циклами, оба цикла дают одинаковый вывод, но третий цикл дает ошибку времени компиляции.

общедоступный тест {

public static void main(String[] args) {
    for (int i = 0; i < 5; i++) {
        final int j= i;
        System.out.println(j);
    }
    for (int i = 0; i < 5; i++) {
        int j= i;
        System.out.println(j);
    }

    final int j;
    for (int i = 0; i < 5; i++) {
        j= i;
        System.out.println(j);
    }
}

}

Пожалуйста, поправьте меня, если я ошибаюсь.

2 голосов
/ 30 апреля 2012

Как ответили, да, вы действительно можете пометить переменные в цикле как «окончательные». Вот результат этого (Java 7, Eclipse Indigo, Mac OS X Lion).

for ( int i = 0; i < 5; i++ ) {

  // With 'final' you cannot assign a new value.
  final int myFinalVariable = i;  // Gets 0, 1, 2, 3, or 4 on each iteration.
  myFinalVariable = 7; // Compiler error: The final local variable myFinalVariable cannot be assigned.

  // Without 'final' you can assign a new value.
  int myNotFinalVariable = i;  // Gets 0, 1, 2, 3, or 4 on each iteration.
  myNotFinalVariable = 7; // Compiler is OK with re-assignment of variable's value.

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