Javaのサブコンテキストは、スタックの列を分離していますか?
質問
Javaではこれが事実です:
public void method() {
if (condition) {
Object x = ....;
}
System.out.println(x); // Error: x unavailable
}
私が疑問に思っているのはこれだと思っています: x
の範囲に限定されています if
- ステートメントJavaコンパイラの機能、または x
実際にスタックから削除されました if
-声明?
解決
いいえ、コードブロックは個別のスタックフレームを取得しません。周囲のメソッドの使用を使用します。
ただし、変数がスコープを離れると、現在のスタックフレーム内の場所を他の変数に対して再利用できます。
スタックフレームの構造と使用は、 Java仮想マシン仕様§3.6フレーム:
メソッドが呼び出されるたびに新しいフレームが作成されます。その完了が正常であろうと突然であろうと、メソッドの呼び出しが完了するとフレームが破壊されます(猛攻撃の例外がスローされます)。
これは、メソッドの呼び出しとフレームの間の1:1の関係を間違いなく指定します。
他のヒント
ブロックはJava言語の一部です(これは 構造化されたプログラミング言語)それらはコンパイルされたbytecodeの一部ではありませんが(これは 非構造 言語).
クラスファイルのメソッド仕様は、実際の命令リストより上に、メソッドが合計で使用するローカル変数の数を指定します。ただし、JavaコードのブロックがBytecodeから推測できない場合。
まず、バイトコードの変数は、スタックではなく変数スロットと変数スロットに保存されます。スロットは別の変数によって再利用できますが、変数スロットから値が削除されることは保証されていません。
たとえば、次のクラス
public class A {
public void method(boolean condition) {
6 if (condition) {
7 Object x = "";
8 System.out.println(x);
9 }
10 System.out.println(condition);
}
}
このbytecodeにコンパイルされています。
// class version 50.0 (50)
public class A {
...
// access flags 0x1
public method(Z)V
L0
LINENUMBER 6 L0
ILOAD 1
IFEQ L1
L2
LINENUMBER 7 L2
LDC ""
ASTORE 2
L3
LINENUMBER 8 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L1
LINENUMBER 10 L1
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ILOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (Z)V
L4
LINENUMBER 11 L4
RETURN
L5
LOCALVARIABLE this LA; L0 L5 0
LOCALVARIABLE condition Z L0 L5 1
LOCALVARIABLE x Ljava/lang/Object; L3 L1 2
MAXSTACK = 2
MAXLOCALS = 3
}
行7で作成された変数xは、10行目に対応するバイトコードでまだ利用可能な変数スロット2に保存されていることに注意してください。
Java言語をどのようにバイトコードにコンパイルする必要があるかについての仕様はありません。ただし、Javaコンパイラは未使用の変数を排除できます。たとえば、xが割り当てられているがどこにも使用されていない場合、コンパイラはそのコードをドロップすることが許可されています。同様に、コンパイラはすべての静的定数をインラリングしています。
はい、それは本当にスタックから削除され、以前に「x」が再利用できるスロットが他のローカル変数によって再利用可能になります。