В 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 (который является языком структурированного программирования ), в то время как они не являются частью скомпилированного байт-кода (который является неструктурированным языком ).
Спецификация метода в файле класса определяет, сколько локальных переменных использует метод в целом, над фактическим списком инструкций. Но где блоки когда-то, где в коде Java, не могут быть выведены из байт-кода.
Да, он действительно удаляется из стека, делая слот, ранее занимаемый 'x', повторно используемым какой-либо другой локальной переменной.
Прежде всего, в байт-коде переменные хранятся в слотах переменных и слотах переменных, а не в стеке. Слот может быть повторно использован другой переменной, но не гарантируется, что значение будет удалено из слота переменной.
Например, следующий класс
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);
}
}
компилируется в этот байт-код:
// 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
}
Обратите внимание, что переменная x, созданная в строке 7, сохраняется в слоте переменной 2, который по-прежнему доступен в байт-коде, соответствующем строке 10.
Нет никаких указаний на то, как язык Java должен быть скомпилирован в байт-код, кроме нескольких примеров того, как правильно компилировать некоторые языковые конструкции. Однако компилятору Java разрешено удалять неиспользуемые переменные. Например. если x был назначен, но нигде не использовался, компилятор может удалить этот код. Точно так же компилятор встраивает все статические константы.