【问题标题】:Question about local final variable in Java关于Java中的局部final变量的问题
【发布时间】:2011-05-10 08:33:24
【问题描述】:

我有以下代码:

public class BookLib {
    void f() {
        final int x = 5; // Line 1
        class MyCLass {
            void print() {
                System.out.println(x);
            }
        }
    }
}

我不明白为什么要在这种情况下使用 final 变量(第 1 行)?

【问题讨论】:

标签: java final


【解决方案1】:

你在这里创建了一个内部类。由于此类对象的生命周期可能比方法调用的运行时间长得多(即对象在方法返回后仍然可以存在很长时间),因此它需要“保留”它的局部变量的状态可以访问。

这种保留是通过在内部类中创建一个(不可见的、合成的)副本并自动将所有对局部变量的引用替换为对该副本的引用来完成的。当创建内部类对象后修改局部变量时,这可能会导致奇怪的效果。

为避免这种情况,要求您以这种方式访问​​的所有局部变量都是final:这可确保局部变量只有一个可能的值,并且不会观察到不一致的情况。

这个具体规则可以在§8.1.3 Inner Classes and Enclosing Instancesthe JLS中找到:

任何使用但未在内部类中声明的局部变量、形式方法参数或异常处理程序参数都必须声明为 final。任何在内部类中使用但未声明的局部变量必须在内部类的主体之前明确分配(§16)

【讨论】:

  • 我们在这里谈论什么奇怪的效果?最终变量是否没有存储在堆栈帧中?
【解决方案2】:

在这里你创建了一个内部类。为了访问执行上下文,对变量的引用应该保持不变,否则会观察到错误行为。为了保证这一点,您应该声明您的变量 final:因此无法更改它。

详细解释见here

【讨论】:

    【解决方案3】:

    来自 kathy sierra scjp 书

    方法的局部变量存在于堆栈中,并且仅在方法的生命周期内存在。我们已经知道,局部变量的作用域仅限于声明变量的方法。当方法结束时,栈帧被吹走,变量就是历史。但是即使在方法完成之后,在其中创建的内部类对象可能仍然在堆上存活,例如,如果对它的引用被传递到其他代码中,然后存储在实例变量中。因为局部变量不保证只要方法局部内部类对象就存活,内部类对象就不能使用它们。除非局部变量被标记为final!

    【讨论】:

      【解决方案4】:

      所以你有一个局部最终变量和局部方法内部类。方法局部内部类不能使用方法中声明的非最终变量(包括参数)。

      要更深入地了解这一点: 方法局部内部类只能在定义类的方法内实例化。局部变量在方法的生命周期内都存在于堆栈中。当方法结束时,局部变量消失了,但是创建的内部类对象仍然存在。

      这是一个生命周期/范围的问题。

      【讨论】:

      • @krookedking 它不能使用在方法中声明的非最终变量(包括参数)。
      • 对不起,我把“不能使用除了最终局部变量”解释为“不能使用除了最终局部变量之外的任何东西”
      • @krookedking 感谢指出,我会更正它,所以它更清楚。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-21
      • 1970-01-01
      • 1970-01-01
      • 2020-06-29
      • 1970-01-01
      • 1970-01-01
      • 2015-02-17
      相关资源
      最近更新 更多