【问题标题】:Referencing non-final variable: why does this code compile?引用非最终变量:为什么这段代码会编译?
【发布时间】:2015-07-20 10:17:00
【问题描述】:

首先,如果这是一个重复的问题,我深表歉意。我发现了很多类似的,但没有一个能直接解决我的问题。

为了准备即将到来的考试,我正在做一份过去的论文。它有一个给出代码sn-p的问题。我们必须说明它是否编译,如果没有,写出第一个编译器错误发生的那一行并解释它。这是sn-p:

public static void main(String[] args) {
    JFrame f = new JFrame("hi");
    JTextField jtf = new JTextField(50);

    jtf.addMouseMotionListener(new MouseMotionAdapter() {
        public void mouseMoved(MouseEvent evt) {
            jtf.setText(evt.getLocationOnScreen().toString());
        }
    });

    f.add(jtf);
    f.setVisible(true);
}

我希望它不会编译为 jtf 不是 final。我通过在 Eclipse 中输入上面的代码来测试我的理论,该代码标记了预期的错误,但编译并运行得很好。只有在将鼠标悬停在JTextField 上之后,我才得到预期的错误:

java.lang.Error:未解决的编译问题: 无法引用封闭范围内定义的非最终局部变量 jtf

我做了一些搜索,发现 Eclipse 使用它自己的 Java 编译器版本。所以我在 Eclipse 之外重新制作了文件并通过命令行编译/运行它。它编译时没有错误或警告,当鼠标悬停在文本字段上时,显示所需的java.awt.Point[x=...,y=...]

我对匿名内部类的理解是可以访问:

  • 封闭类的字段
  • 封闭类的方法
  • 封闭范围的局部变量,只要它们是final

那么我错过了什么?据我所知,这段代码应该不起作用

【问题讨论】:

    标签: java java-8 inner-classes


    【解决方案1】:

    我猜你正在使用 Java 8 进行编译。这里你的 jtf 变量实际上是最终的,所以它编译得很好。如果变量在初始化后从未更改,则它实际上是最终变量。

    另见Local Classes

    但是,从 Java SE 8 开始,本地类可以访问本地 封闭块的变量和参数是最终的或 有效地最终。一个变量或参数,其值从不 初始化后更改实际上是最终的。

    Accessing Local Variables of the Enclosing Scope, and Declaring and Accessing Members of the Anonymous Class

    和本地类一样,匿名类可以捕获变量;他们有 对封闭范围的局部变量的相同访问:

    • 匿名类可以访问其封闭类的成员。

    • 匿名类无法访问其封闭的局部变量 未声明为最终或有效最终的范围。

    [...]

    如果你尝试过:

    javac -source 1.7 MyFile.java
    

    您将遇到预期的错误。

    .java:13: error: local variable jtf is accessed from within inner class; needs to be declared final
                    jtf.setText(evt.getLocationOnScreen().toString());
                    ^
    1 error
    

    所以考试问题的答案是:它只有在你使用 Java 8+ 时才能编译。

    【讨论】:

      【解决方案2】:

      您的 Eclipse IDE 似乎使用 Java 7 编译器。要将其更改为 Java 8,请使用 Project->Properties->Java Compiler->Compiler compliance level。

      【讨论】:

        【解决方案3】:

        它可能在Java8 中起作用,因为压力在Effectively Final 上,这意味着一旦将值分配给jtf,它就不应在病房后更改。根据 Java 文档:

        一个变量或参数,其值在它被改变后永远不会改变 初始化实际上是最终的。

        【讨论】:

          【解决方案4】:

          Java 8 添加了访问"effectively final" 变量的功能。只要变量在初始化后从未更改,就不再需要 final 关键字。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-18
            • 2011-12-27
            • 1970-01-01
            • 1970-01-01
            • 2012-07-06
            • 2013-08-08
            相关资源
            最近更新 更多