在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代码不能被从字节码推断。

首先,在字节码中变量存储在变量时隙和可变的槽,而不是在堆栈。槽可以通过另一个变量被重新使用,但是它不保证该值将从可变时隙被删除。

例如,下面的类

  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
}

请注意,在第7行X创建的变量被存入可变时隙2,它仍然是可用的在对应于第10行的字节码。

有是Java语言怎么也得被编译成字节码,然后其他几个例子,如何正确地编译一些语言结构不规范。但是Java编译器允许删除未使用的变量。例如。如果x被分配,而不是在任何地方使用,编译器允许下降代码。类似地,编译器是内联的所有静态常数。

是,它实际上从堆栈中移除使得先前由“X”可重复使用的一些其他本地变量占用的插槽。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top