Создание конечных переменных внутри цикла
это разрешено в java:
for(int i=0;i<5;i++){
final int myFinalVariable = i;
}
Ключевое слово моего вопроса: final
. Разрешено ли делать конечную переменную, которая изменяется при каждом запуске цикла? Мне было интересно, потому что в финале говорится, что вы не можете изменить значение переменной (только для вызова myFinalVariable = i
), но я переопределяю всю переменную с помощью final int
.
Являются ли они двумя совершенно разными переменными с одним и тем же именем - с переменной из предыдущего прогона цикла, уже направляющегося по дороге в сборщик мусора?
Ответы
Ответ 1
Да, это разрешено. Ключевое слово final
означает, что вы не можете изменить значение переменной в своей области. В примере вашего цикла вы можете думать о переменной, выходящей из области действия в нижней части цикла, а затем возвращаться в область видимости с новым значением в верхней части цикла. Назначение переменной внутри цикла не будет работать.
Ответ 2
Вы правы, для каждой итерации в цикле вы создаете новую переменную. Переменные имеют одно и то же имя, но это прекрасно, потому что они не находятся в одной области. Следующий пример не будет работать:
final int myFinalVariable = 0;
for(int i=0;i<5;i++){
myFinalVariable = i;
}
Ответ 3
Переменная - это просто место в стеке. Постарайтесь, чтобы ваши переменные были как можно меньше, и попытайтесь сделать их окончательными. Однако объем и конечный результат - это всего лишь исходные коды... с точки зрения генерации кода /VM они вообще не имеют значения.
В вашем конкретном примере, используя "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
}
Ответ 4
Переменная, объявленная внутри цикла, имеет область действия только до однократного выполнения цикла.
Объявление переменной как окончательной внутри цикла делает разницу для переменной в стороне цикла, но если мы объявим переменную вне цикла с окончательным модификатором, тогда значение, присвоенное примитивному типу или объекту, назначенное ссылочной переменной, не может быть изменено.
В приведенном ниже примере нет проблем с первыми двумя циклами, и циклы дают одинаковый вывод, но третий цикл дает время компиляции Error.
публичный тест класса {
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);
}
}
}
Пожалуйста, поправьте меня, если я ошибаюсь.
Ответ 5
Как уже было сказано, да, вы действительно можете пометить переменные в цикле как "final". Вот как это работает (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 value.
}