簡単に言うと、ローカル変数とパラメーターでキーワードを使用するfinal
と、生成されたバイトコード (ファイル) に到達せず、予想どおり、その使用は実行時に影響しません。(コンパイル時に、違いが生じる可能性がありますが、以下を確認してください。).class
これらの場合、匿名の内部クラスのために強制されない場合、それは単なるスタイルの選択であり、変数の意図したスコープを文書化するのに役立ちます。
以下のテストは、その情報を確認します。
1: コンパイラが何かを作ることができる場合、使用final
することで違いが生まれます:
このスニペットを見てください:
boolean zZ = true;
while (zZ) {
int xX = 1001; // <------------- xX
int yY = 1002; // <------------- yY
zZ = (xX == yY);
}
2 つのint
変数、xX
およびyY
. 最初は両方を asfinal
と宣言し、2 回目は両方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
かどうかをコンパイラ時間に伝えることができませんよね?xX
yY
このため、生成されたバイトコードは、 を使用してクラスを生成しても使用せずに生成しても、まったく同じ(同じ MD5!) であることがわかります。final
一般的なケースでは、 を使用するとパフォーマンス上の利点があると言う人もいれば反対する人もいますが、ローカル ブロックで を使用することは間違いなく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);
}
...まったく同じです(もちろん、行番号だけが変更されました)。
(プリミティブ型の変数だけでなく) オブジェクトを使用した他のテストでも、同じ動作が示されました。
他の場所で使用されていない場合、ループ内またはループ外でローカル変数を宣言することは、バイトコードの影響がなく、ほとんど設計上の選択であると結論付けても安全です。
注:すべてのテストは、Oracle の JRE、バージョン 1.7.0_13 で行われました。