First of all, in the bytecode variables are stored in the variable slots and variable slots and not on the stack. The slot could be reused by another variable, but it is not guaranteed that value would be removed from the variable slot.
For example, the following class
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);
}
}
is compiled into this 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
}
Note that variable x created at line 7 is stored into the variable slot 2, which is still available at the bytecode corresponding to line 10.
There is no specification on how Java language have to be compiled into the bytecode other then few examples how to properly compile some language constructs. However Java compiler is allowed to eliminate unused variables. E.g. if x were assigned, but not used anywhere, compiler is allowed to drop that code. Similarly, compiler is inlining all the static constants.