В нескольких словах:final
ключевое слово, при использовании локальных переменных и параметров , не попадает в сгенерированный байт-код (файл .class
) и, как ожидается, его использование не влияет на время выполнения. (Compile время, он мог бы сделать различию, хотя, проверьте ниже.)
В тех случаях, когда не выполняются из-за анонимные внутренние классы, это просто стиля выбора, полезный в документировании предполагаемога область действия переменной.
Приведенные ниже тесты подтверждают эту информацию.
1: Если компилятор может сделать что-то из этого, используя final
делает различие:
Посмотрите на этот фрагмент:
boolean zZ = true;
while (zZ) {
int xX = 1001; // <------------- xX
int yY = 1002; // <------------- yY
zZ = (xX == yY);
}
Два int
переменных, xX
и yY
. Первый раз объявили как final
, и во второй раз забрали final
от обоих. Вот генерируемые байткоды (печатные с javap -c
):
И final
:
0: iconst_1 // pushes int 1 (true) onto the stack
1: istore_1 // stores the int on top of the stack into var zZ
2: goto 15
5: sipush 1001 // pushes 1001 onto the operand stack
8: istore_2 // stores on xX
9: sipush 1002 // pushes 1002 onto the operand stack
12: istore_3 // stores on yY
13: iconst_0 // pushes 0 (false): does not compare!! <---------
14: istore_1 // stores on zZ
15: iload_1 // loads zZ
16: ifne 5 // goes to 5 if top int (zZ) is not 0
19: return
Оба не- final
:
// 0: to 12: all the same
13: iload_2 // pushes xX onto the stack
14: iload_3 // pushes yY onto the stack
15: if_icmpne 22 // here it compares xX and yY! <------------
18: iconst_1
19: goto 23
22: iconst_0
23: istore_1
24: iload_1
25: ifne 5
28: return
В приведенном выше случае, когда они final
, компилятор знает, что они не равны и никогда их не сравнивают (false
генерируется в байт-коде где угодно xX == yY
).
Из этого мы можем заключить, байткод мудрые, компилятор делает может сделать некоторую оптимизацию генерируемого кода при использовании final
. (Я не говорю, что они имеют смысл, но наверняка final
не только стиль выбор здесь.)
2: Если компилятор не может ничего сделать вывод, используя final
на местном Варс это просто дизайн выбор:
Теперь возьмите следующий код:
boolean zZ = true;
int aA = 1001;
int bB = 1002;
while (zZ) {
final int xX = aA; // <------- took away the "final" here, didnt matter
final int yY = bB; // <------- took away the "final" here, didnt matter
zZ = (xX == yY);
}
В этом случае, даже при использовании final
, компилятор annot рассказать компилятор-время, если xX
и yY
равны, верно?
Из-за этого, мы можем видеть: сгенерированный байткод точно такой же, когда мы создаем класс с или без final
(такой же MD5!).
Хотя, в общем случае , some say и others disagree, что есть преимущества в производительности использования final
, в локальных блоках, final
, безусловно, только стиля выбор.
3: Локальные переменные внутри или снаружи петли - нет никакой разницы на всех:
Сформированный байткод для этого фрагмента ...
boolean zZ = true;
int aA = 1001, bB = 1002;
while (zZ) {
int xX = aA; // <--- declaration is inside WHILE
int yY = bB;
zZ = (xX == yY);
}
... и сгенерированный байткод для этого фрагмента ...
boolean zZ = true;
int aA = 1001, bB = 1002;
int xX, yY; // <--- declaration is outside WHILE
while (zZ) {
xX = aA;
yY = bB;
zZ = (xX == yY);
}
... являются точно такими же (только номера строк изменились, конечно).
Другие тесты с использованием объектов (а не только примитивные типизированные переменные) показали одинаковое поведение.
Безопасно заключить, если они не используются в других местах, объявления локальных переменных внутри или снаружи петли довольно много Избранный дизайн, без байткодом эффектов.
Примечание: Все испытания проводились под JRE Oracle, версия 1.7.0_13.
Предположительно он выполняет ту же задачу, что и в другом месте: при попытке изменить переменную компилятор останавливает вас. – Cairnarvon
Эта переменная * очень * локальная (только для тела цикла). Он даже не упоминается нигде в одном цикле. Защищает ли это читаемость, запрещая повторное использование для другой цели? –