質問
これはjavaで許可されています:
for(int i=0;i<5;i++){
final int myFinalVariable = i;
}
私の質問のキーワードは final
です。ループの実行ごとに変化する最終変数を実行できますか? finalは変数の値を変更できない( myFinalVariable = i
のみを呼び出す)と言っているので、これを疑問に思っていましたが、 final int
。
これらは、同じ名前の2つの完全に異なる変数ですか?前のループの実行からの変数が既にガベージコレクターに向かっていますか?
解決
はい、許可されています。 final
キーワードは、スコープ内で変数の値を変更できないことを意味します。ループの例では、ループの下部で変数がスコープから出て、ループの上部で新しい値でスコープに戻ると考えることができます。ループ内の変数への割り当ては機能しません。
他のヒント
あなたは正しいです。ループの各反復に対して、新しい変数を作成しています。変数は同じ名前を共有しますが、同じスコープ内にないので問題ありません。次の例は動作しません :
final int myFinalVariable = 0;
for(int i=0;i<5;i++){
myFinalVariable = i;
}
変数は、スタック上の単なる場所です。できるだけ小さなスコープで変数を維持し、最終的なものにするようにしてください。ただし、スコープとファイナルは単なるソースコードです。コード生成/ VMの観点からは、それらはまったく問題ではありません。
特定の例では、&quot; int&quot;を使用します。ゴミは作成されません。ただし、オブジェクトが作成されている場合は、どちらの場合でも、ガベージの量と、ガベージがクリーンアップの対象になる時期は同じです。
次のコードを取得します。
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
}
答えたとおり、はい、ループ内の変数を実際に「最終」としてマークできます。これがその結果です(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.
}
ループ内で宣言された変数の有効範囲は、ループが1回実行されるまでです。
ループ内で変数をfinalとして宣言しても、ループ内の変数には違いはありませんが、最終修飾子を使用してループ外で変数を宣言すると、プリミティブ型に割り当てられた値または参照変数に割り当てられたオブジェクトは変更されます。
次の例では、最初の2つのループに問題はありません。両方のループは同じ出力を提供しますが、3番目のループではコンパイル時エラーが発生します。
パブリッククラステスト{
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);
}
}
}
間違っている場合は修正してください。